/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */ 
/** NetX Component                                                        */ 
/**                                                                       */
/**   Simple Network Management Protocol (SNMP)                           */ 
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

#define NX_SNMP_SOURCE_CODE

/* Force error checking to be disabled in this module */

#ifndef NX_DISABLE_ERROR_CHECKING
#define NX_DISABLE_ERROR_CHECKING
#endif

/* Include necessary system files.  */

#include    "nx_api.h"
#include    "nx_snmp.h"



/* To enable debug output, define this option.  
#define NX_SNMPV3_PRINT_DEBUG_MESSAGE
*/

#define NX_SNMP_REQUEST_AUTH_SIZE 50 

#ifndef NX_SNMP_DISABLE_V3
/* Define locations in request buffer PDU in the event we need
   to return the message e.g. error message response. */
static UINT   pdu_length; 
static UCHAR *pdu_buffer_ptr; 
static UCHAR *pdu_auth_parm_ptr;
static UCHAR *pdu_privacy_ptr; 
#endif

/* Enable or disable SNMPv3 debug message printout.  */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    #define NX_SNMPV3_DBG_PRINTF printf 
#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE */


/* Define global SNMP variables and strings.  */

/* If the array size of _nx_snmp_v2_trap_ids is changed, these upper limit MUST by updated! */
#define TRAP_ID_MAX  5
UCHAR *_nx_snmp_v2_trap_ids[] =  {  (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart)                */,   
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart)                */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown)                 */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp)                   */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure)    */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss)          */
                                 };



#ifndef NX_SNMP_DISABLE_V3

UCHAR *_nx_snmp_v3_trap_ids[] =  {  (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart)                */, 
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart)                */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown)                 */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp)                   */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure)    */,
                                    (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss)          */
                                 };

/* Define the default context engine information. This will be setup when the SNMP agent is
   created. Note that this information isn't used for SNMP v1 and v2.  Note the host application
   should use the nx_snmp_agent_context_engine_set() service to set its own IPv4 (or MAC address
   depending on format type) when creating the Engine ID. The engine size must match the total engine
   data including the input context engine data as well. See documentation for more details.  

   Note that this information isn't used for SNMP v1 and v2.  */
      
UCHAR  _nx_snmp_default_context_engine[NX_SNMP_MAX_CONTEXT_STRING] =  {0x80, 0x00, 0x03, 0x10, 0x01, 0xc0, 0xa8, 0x64, 0xaf};
UINT   _nx_snmp_default_context_engine_size =  9;

CHAR   _nx_snmp_default_initial_user_name[] =  "initial";  

#endif

/* As per RFC 3414 for SNMPv3 the discovery report must include the usmStats variables. */
#define     NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC        "1.3.6.1.6.3.15.1.1.1.0" 
#define     NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM    1
#define     NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME        "1.3.6.1.6.3.15.1.1.2.0"
#define     NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM    2
#define     NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME       "1.3.6.1.6.3.15.1.1.3.0"
#define     NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM   3
#define     NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID       "1.3.6.1.6.3.15.1.1.4.0"
#define     NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM   4

/* Define the maximum difference between local time (in seconds) and browser notion of 
   local time recommended by RFC 3413. */
#define     NX_SNMP_TIME_WINDOW                          150 


/* Bring in externs for caller checking code.  */

NX_CALLER_CHECKING_EXTERNS


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_authenticate_key_use                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP authentication key      */ 
/*    specification function call.  To disable authentication, set        */ 
/*    the key pointer to null.                                            */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Authenticate key              */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_authenticate_key_use   Actual authentication key     */ 
/*                                            setup function              */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
    {
    
        return(NX_PTR_ERROR);
    }

    if (key != NX_NULL)
    {

        /* Check for valid authentication type. */
        if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY))
        {
            return NX_SNMP_UNSUPPORTED_AUTHENTICATION;
        }
    }

    /* Call actual service.  */
    status =  _nx_snmp_agent_authenticate_key_use(agent_ptr, key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_authenticate_key_use                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets up the authenticate key to use for checking the  */ 
/*    digest of the request.                                              */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Authenticate key              */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

#ifdef NX_SNMP_NO_SECURITY
    return NX_NOT_ENABLED;
#else

    /* Set the authenticate pointer so authentication will use the specified key.  Note this
       key must have been created prior to calling this routine.  */
    agent_ptr -> nx_snmp_agent_v3_authentication_key =  key;

    /* Return success to the caller.  */
    return(NX_SUCCESS);
#endif
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_trap_auth_key_use                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function is the error checking service for the setting the trap*/
/*    message authentication key. To disable trap key authentication, set */ 
/*    the key pointer to null.                                            */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Authenticate key for traps    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_auth_trap_key_use      Actual set trap authentication*/
/*                                               key service              */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
    {
    
        return(NX_PTR_ERROR);
    }

    if (key != NX_NULL)
    {
    
        /* Check for invalid authentication type. */
        if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY))
        {
    
            return NX_SNMP_UNSUPPORTED_AUTHENTICATION;
        }
    }

    /* Call actual service.  */
    status =  _nx_snmp_agent_auth_trap_key_use(agent_ptr, key);

    /* Return status.  */
    return(status);
}

/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_auth_trap_key_use                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets up the authenticate key to use for creating      */
/*    authentication parameters in SNMPv3 trap messages.                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Authenticate key for traps    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT    _nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

#ifdef NX_SNMP_NO_SECURITY
    return NX_NOT_ENABLED;
#else 


    /* Set the authenticate pointer so authentication will use the specified key.  Note this
       key must have been created prior to calling this routine.  */
    agent_ptr -> nx_snmp_agent_v3_auth_trap_key =  key;
    
    /* Return success to the caller.  */
    return(NX_SUCCESS);

#endif
}
#endif /* NX_SNMP_DISABLE_V3 */


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_community_get                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP community get           */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string_ptr                  Pointer to the community      */ 
/*                                            string destination          */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_community_get          Actual community get function */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (community_string_ptr == NX_NULL))
        return(NX_PTR_ERROR);
    
    /* Call actual service.  */
    status =  _nx_snmp_agent_community_get(agent_ptr, community_string_ptr);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_community_get                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the community string.                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string_ptr                  Pointer to the community      */ 
/*                                            string destination          */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr)
{

    /* Set a pointer to the community string for the caller.  */
    *community_string_ptr =  agent_ptr -> nx_snmp_agent_current_community_string;

    /* Return successful status.  */
    return(NX_SUCCESS);
}


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_context_engine_set                  PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP context engine set      */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    context_engine                        Pointer to context engine     */ 
/*    context_engine_size                   Number of bytes in the        */ 
/*                                            context engine              */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_context_engine_set     Actual context engine set     */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (context_engine == NX_NULL))
        return(NX_PTR_ERROR);
    
    /* Check for an invalid size.  */
    if ((context_engine_size == 0) || (context_engine_size >= NX_SNMP_MAX_CONTEXT_STRING))
        return(NX_SNMP_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_context_engine_set(agent_ptr, context_engine, context_engine_size);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_context_engine_set                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the context engine of the specified SNMP agent.  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    context_engine                        Pointer to context engine     */ 
/*    context_engine_size                   Number of bytes in the        */ 
/*                                            context engine              */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size)
{

UINT    i;


    /* Verify V3 is currently enabled for this agent. */
    if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE)
    {
        return NX_NOT_ENABLED;
    }

    /* Determine if the context engine is the correct size.  */
    if (context_engine_size > NX_SNMP_MAX_CONTEXT_STRING)
    {

        /* Return an error.  */
        return(NX_SNMP_ERROR);
    }

    /* Otherwise, store the context engine.  */
    for (i = 0; i < context_engine_size; i++)
    {

        /* Store a byte of the context engine.  */
        agent_ptr -> nx_snmp_agent_v3_context_engine[i] =  context_engine[i];
    }

    /* Set the context engine length.  */
    agent_ptr -> nx_snmp_agent_v3_context_engine_size =  context_engine_size;

    /* Return successful completion.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_context_name_set                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP context name set        */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    context_name                          Pointer to context name       */ 
/*    context_name_size                     Number of bytes in the        */ 
/*                                            context name                */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_context_name_set       Actual context name set       */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Initialization                                                      */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (context_name == NX_NULL))
        return(NX_PTR_ERROR);
    
    /* Check for an invalid size.  */
    if ((context_name_size == 0) || (context_name_size >= NX_SNMP_MAX_USER_NAME))
        return(NX_SNMP_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_context_name_set(agent_ptr, context_name, context_name_size);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_context_name_set                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the context name of the specified SNMP agent.    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    context_name                          Pointer to context name       */ 
/*    context_name_size                     Number of bytes in the        */ 
/*                                            context name                */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Initialization                                                      */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size)
{

UINT    i;

    /* Determine if the context name is the correct size.  */
    if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING)
    {

        /* Return an error.  */
        return(NX_SNMP_ERROR);
    }

    /* Otherwise, store the context name.  */
    for (i = 0; i < context_name_size; i++)
    {

        /* Store a byte of the context name.  */
        agent_ptr -> nx_snmp_agent_v3_context_name[i] =  context_name[i];
    }

    /* Set the context name length.  */
    agent_ptr -> nx_snmp_agent_v3_context_name_size =  context_name_size;

    /* Return successful completion.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_v3_context_boots_set                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP context boots set       */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    boots                                 Value to set agent boots to   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_PTR_ERROR                          Invalid pointer input         */ 
/*    NX_SNMP_ERROR                         Invalid boot count input      */
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_v3_context_boots_set    Actual context boots set      */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Initialization                                                      */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots)
{

UINT    status;


    /* Check for invalid input pointer.  */
    if (agent_ptr == NX_NULL) 
        return(NX_PTR_ERROR);
    
    /* Call actual service.  */
    status =  _nx_snmp_agent_v3_context_boots_set(agent_ptr, boots);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_v3_context_boots_set                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the context boot count of the specified SNMP     */ 
/*    agent.                                                              */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    boots                                 Value to set agent boots to   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*    NX_SNMP_ERROR                         Invalid boot count input      */
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Initialization                                                      */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots)
{

    /* Set the context name length.  */
    agent_ptr -> nx_snmp_agent_v3_context_engine_boots =  boots;

    /* Return successful completion.  */
    return(NX_SUCCESS);
}

#endif


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_create                              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent create            */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    snmp_agent_name                       Name of SNMP agent            */ 
/*    ip_ptr                                Pointer to IP instance        */ 
/*    stack_ptr                             Pointer to stack for SNMP     */ 
/*                                            thread                      */ 
/*    stack_size                            Size in bytes of thread stack */ 
/*    pool_ptr                              Default packet pool           */ 
/*    snmp_agent_username_process           Username callback routine     */ 
/*    snmp_agent_get_process                Get callback routine          */ 
/*    snmp_agent_getnext_process            Getnext callback routine      */ 
/*    snmp_agent_set_process                Set callback routine          */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_create                 Actual agent create function  */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
                UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username),
                UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data),
                UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data),
                UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data))
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id == NX_SNMP_ID) || (ip_ptr == NX_NULL) || (stack_ptr == NX_NULL) ||
        (pool_ptr == NX_NULL) || (!snmp_agent_username_process) || (!snmp_agent_get_process) || (!snmp_agent_getnext_process) || (!snmp_agent_set_process))
        return(NX_PTR_ERROR);

    /* Check for an invalid size.  */
    if (stack_size == 0)
        return(NX_SNMP_ERROR);
    
    /* Call actual service.  */
    status =  _nx_snmp_agent_create(agent_ptr, snmp_agent_name, ip_ptr, stack_ptr, stack_size, pool_ptr,
                    snmp_agent_username_process, snmp_agent_get_process, snmp_agent_getnext_process, snmp_agent_set_process);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_create                               PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function creates an SNMP agent.                                */ 
/*                                                                        */ 
/*    Note: The string length of username in snmp_agent_username_process  */ 
/*    callback is limited by NX_SNMP_MAX_USER_NAME.                       */ 
/*    The string length of object_requested in snmp_agent_get_process,    */ 
/*    snmp_agent_getnext_process and snmp_agent_set_process callback is   */ 
/*    limited by NX_SNMP_MAX_OCTET_STRING.                                */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    snmp_agent_name                       Name of SNMP agent            */ 
/*    ip_ptr                                Pointer to IP instance        */ 
/*    stack_ptr                             Pointer to stack for SNMP     */ 
/*                                            thread                      */ 
/*    stack_size                            Size in bytes of thread stack */ 
/*    pool_ptr                              Default packet pool           */ 
/*    snmp_agent_username_process           Username callback routine     */ 
/*    snmp_agent_get_process                Get callback routine          */ 
/*    snmp_agent_getnext_process            Getnext callback routine      */ 
/*    snmp_agent_set_process                Set callback routine          */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_udp_socket_bind                    Bind SNMP agent socket        */ 
/*    nx_udp_socket_create                  Create SNMP agent socket      */ 
/*    nx_udp_socket_delete                  Delete SNMP agent socket      */ 
/*    nx_udp_socket_unbind                  Unbind SNMP agent socket      */
/*    tx_thread_create                      Create SNMP agent thread      */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
                UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username),
                UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data),
                UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data),
                UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data))
{

UINT        status;

#ifndef NX_SNMP_DISABLE_V3
UINT        i;
#endif


#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF( "Creating snmp agent of size %d\n\r", stack_size);
#endif

    /* Clear the SNMP agent structure.  */
    memset((void *) agent_ptr, 0, sizeof(NX_SNMP_AGENT));

    /* Create the agent's UDP socket.  */
     status =  nx_udp_socket_create(ip_ptr, &(agent_ptr -> nx_snmp_agent_socket), snmp_agent_name,
                                    NX_SNMP_TYPE_OF_SERVICE,  NX_SNMP_FRAGMENT_OPTION, 
                                    NX_SNMP_TIME_TO_LIVE, NX_SNMP_QUEUE_DEPTH);

     /* Determine if an error occurred.   */
     if (status)
     {

         /* Yes, return error code.  */
         return(NX_SNMP_ERROR);
     }

    /* Now create the SNMP Server thread.  */
    status =  tx_thread_create(&(agent_ptr -> nx_snmp_agent_thread), "SNMP Agent Thread", _nx_snmp_agent_thread_entry, 
            (ULONG) agent_ptr, stack_ptr, stack_size, NX_SNMP_AGENT_PRIORITY, NX_SNMP_AGENT_PRIORITY, 
            TX_NO_TIME_SLICE, TX_DONT_START);

    /* Determine if an error occurred creating the thread.  */
    if (status)
    {

         /* Delete the UDP socket.  */
         nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket));

        /* Yes, return error code.  */
        return(NX_SNMP_ERROR);
    }

    /* Save the Server name.  */
    agent_ptr -> nx_snmp_agent_name =  snmp_agent_name;

    /* Save the IP pointer address.  */
    agent_ptr -> nx_snmp_agent_ip_ptr =  ip_ptr;

    /* Save the packet pool pointer.  */
    agent_ptr -> nx_snmp_agent_packet_pool_ptr =  pool_ptr;

    /* Default the SNMP network interface to the primary interface. */
    agent_ptr -> nx_snmp_agent_interface_index = 0;

    /* Initialize the agent as configured for all versions. 

       Note that the #define options for disabling version support override dynamic version status. 

       For example if  NX_SNMP_DISABLE_V2 is disabled, setting nx_snmp_agent_v2_enabled 
       to NX_TRUE has no effect. If NX_SNMP_DISABLE_V2 is not disabled, then 
       nx_snmp_agent_v2_enabled determines at run time if the SNMP is enabled for V2.*/

    agent_ptr -> nx_snmp_agent_v1_enabled = NX_TRUE;                       
    agent_ptr -> nx_snmp_agent_v2_enabled = NX_TRUE;                       
    agent_ptr -> nx_snmp_agent_v3_enabled = NX_TRUE; 


#ifndef NX_SNMP_DISABLE_V3

    /* Setup the SNMP v3 information.  */

    /* Setup the default context engine.  */
    for (i = 0; i < _nx_snmp_default_context_engine_size; i++)
    {

        /* Copy byte of default context engine.  */
        agent_ptr -> nx_snmp_agent_v3_context_engine[i] =  _nx_snmp_default_context_engine[i];
    }

    /* Set the default context engine size.  */
    agent_ptr -> nx_snmp_agent_v3_context_engine_size =   _nx_snmp_default_context_engine_size;

    /* Start the time (in ticks) since the previous reboot. */
    agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);

#endif /* NX_SNMP_DISABLE_V3 */

    /* Save the application request processing callback routines.  */
    agent_ptr -> nx_snmp_agent_get_process =      snmp_agent_get_process;
    agent_ptr -> nx_snmp_agent_getnext_process =  snmp_agent_getnext_process;
    agent_ptr -> nx_snmp_agent_set_process =      snmp_agent_set_process;
    agent_ptr -> nx_snmp_agent_username_process = snmp_agent_username_process;

    /* Set the agent ID to indicate the SNMP agent thread is ready.  */
    agent_ptr -> nx_snmp_agent_id =  NX_SNMP_ID;

    /* Return successful completion.  */
    return(NX_SUCCESS);
}

/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_request_get_type_test               PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent get current       */ 
/*    request type.                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    is_get_type                           Pointer to request type       */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_request_get_type_test  Actual request type service   */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type)
{
UINT status;

    if ((agent_ptr == NX_NULL) || (is_get_type == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_request_get_type_test(agent_ptr, is_get_type);
    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_request_get_type_test                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function indicates if the current request recieved from the    */
/*    SNMP manager is a Get type (GET, GETNEXT etc) of a SET type. It is  */
/*    intended for use in the username_callback for the host application  */
/*    to process the request for matching community string (private for   */
/*    set requests, public for get requests).                             */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    is_get_type                           Pointer to request type       */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type)
{

    *is_get_type = agent_ptr -> nx_snmp_agent_request_get_type;
       
    return NX_SUCCESS;
}

/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_delete                              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent delete            */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_delete                 Actual agent delete function  */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_delete(agent_ptr);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_delete                               PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function deletes the previously created SNMP agent.            */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_udp_socket_delete                  Delete SNMP agent socket      */ 
/*    nx_udp_socket_unbind                  Unbind SNMP agent socket      */
/*    tx_thread_delete                      Delete SNMP agent thread      */ 
/*    tx_thread_terminate                   Terminate SNMP agent thread   */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr)
{

    /* Terminate the SNMP thread.  */
    tx_thread_terminate(&(agent_ptr -> nx_snmp_agent_thread));

    /* Delete the SNMP thread.  */
    tx_thread_delete(&(agent_ptr -> nx_snmp_agent_thread));

    /* Unbind the UDP socket.  */
    nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket));

    /* Delete the UDP socket.  */
    nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket));

    /* Clear the agent ID to indicate the SNMP agent is deleted.  */
    agent_ptr -> nx_snmp_agent_id =  0;

    /* Return successful completion.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_current_version_get                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for the get the received      */ 
/*    packet SNMP version service.                                        */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    version                               Pointer to packet SNMP version*/ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_PTR_ERROR                          Invalid pointer input         */
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_current_version_get    Actual get version service    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version)
{
UINT status;

    if ((agent_ptr == NX_NULL) || (version == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_current_version_get(agent_ptr, version);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_current_version_get                  PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function returns the received packet's SNMP version.           */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    version                               Pointer to packet SNMP version*/ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion         */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version)
{

    *version = agent_ptr -> nx_snmp_agent_current_version;

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_set_version                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for (dis)enabling the SNMP    */ 
/*    agent for SNMPV1, SNMPV2 and SNMPV3.                                */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    enabled_v1                            V1 enable status              */ 
/*    enabled_v2                            V2 enable status              */ 
/*    enabled_v3                            V3 enable status              */ 
/*                                          Enable = 1 (NX_TRUE)          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_PTR_ERROR                          Invalid pointer input         */
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3)
{
UINT status;

    /* Check for invalid input */
    if (agent_ptr == NX_NULL)
    {
        return NX_PTR_ERROR;
    }

    /* Call the actual service. */
    status = _nx_snmp_agent_version_set(agent_ptr, enabled_v1, enable_v2, enable_v3);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_version_set                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the SNMP agent status for SNMPV1, SNMPV2 and     */
/*    SNMPV3.                                                             */ 
/*                                                                        */ 
/*    Note that the #define options for disabling version support override*/  
/*    dynamic version status.                                             */
/*                                                                        */ 
/*    For example if  NX_SNMP_DISABLE_V2 is disabled, setting             */
/*    nx_snmp_agent_v2_enabled to NX_TRUE has no effect. If               */
/*    NX_SNMP_DISABLE_V2 is not disabled, then nx_snmp_agent_v2_enabled   */
/*    determines at run time if the SNMP is enabled for V2.               */
/*                                                                        */
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    enabled_v1                            V1 enable status              */ 
/*    enabled_v2                            V2 enable status              */ 
/*    enabled_v3                            V3 enable status              */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion         */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3)
{

    /* Set the agent status for each of the SNMP versions. */
    agent_ptr -> nx_snmp_agent_v1_enabled = enabled_v1;

    agent_ptr -> nx_snmp_agent_v2_enabled = enable_v2;

    agent_ptr -> nx_snmp_agent_v3_enabled = enable_v3;

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_set_interface                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the SNMP network interface for the SNMP agent.   */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    if_index                              SNMP network interface index  */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index)
{
UINT status;

    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_set_interface(agent_ptr, if_index);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_set_interface                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the SNMP network interface for the SNMP agent.   */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    if_index                              SNMP network interface index  */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index)
{

    agent_ptr -> nx_snmp_agent_interface_index = if_index;

    return NX_SUCCESS;
}


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_md5_key_create                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP md5 key create          */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the MD5 key      */ 
/*    destination_key                       Destination for the MD5 key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_md5_key_create         Actual agent MD5 key create   */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (password == NX_NULL) || (destination_key == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_md5_key_create(agent_ptr, password, destination_key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_md5_key_create                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function creates an MD5 key.                                   */ 
/*                                                                        */ 
/*    Note: new API nx_snmp_agent_md5_key_create_extended is encouraged   */ 
/*    to use.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the MD5 key      */ 
/*    destination_key                       Destination for the MD5 key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_utility_string_length_check       Check string length           */ 
/*    _nx_snmp_agent_md5_key_create_extended Agent MD5 key create function*/ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key)
{


/* Verify SNMP security is not disabled for this project. */
#ifdef NX_SNMP_NO_SECURITY
    /* Security is not supported, clear the key and return an error.  */
    destination_key -> nx_snmp_security_key_type =   0;
    destination_key ->  nx_snmp_security_key_size =  0;

    /* Return an error.  */
    return(NX_NOT_ENABLED);
#else

UINT        status;
UINT        password_length;


    /* Calculate the password length.  */
    if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH))
    {
        return(NX_SIZE_ERROR);
    }

    /* Check length of password. */
    if (password_length == 0)
    {
        return(NX_SNMP_FAILED);
    }

    /* Call actual service.  */
    status = _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key);

    /* Return status to the caller.  */
    return(status);
#endif
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_md5_key_create_extended             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP md5 key create          */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the MD5 key      */ 
/*    password_length                       Length of password            */ 
/*    destination_key                       Destination for the MD5 key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_md5_key_create_extended                              */ 
/*                                          Actual agent MD5 key create   */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_md5_key_create_extended              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function creates an MD5 key.                                   */ 
/*                                                                        */
/*    Note: The string of password must be NULL-terminated and length     */
/*    of string matches the length specified in the argument list.        */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the MD5 key      */ 
/*    password_length                       Length of password            */ 
/*    destination_key                       Destination for the MD5 key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_md5_initialize                    Initialize the MD5 algorithm  */ 
/*    _nx_md5_update                        MD5 algorithm update          */ 
/*    _nx_md5_digest_calculate              Calculate the MD5 key         */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key)
{


/* Verify SNMP security is not disabled for this project. */
#ifdef NX_SNMP_NO_SECURITY
    /* Security is not supported, clear the key and return an error.  */
    destination_key -> nx_snmp_security_key_type =   0;
    destination_key ->  nx_snmp_security_key_size =  0;

    /* Return an error.  */
    return(NX_NOT_ENABLED);
#else

NX_MD5      MD;
UCHAR      *cp, password_buf[64];
ULONG       password_index = 0;
ULONG       count = 0, i;
UINT        temp_password_length;


    /* Get the length of password string.  */
    if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length))
        return(NX_SNMP_FAILED);

    /* Check the password string length.  */
    if (password_length != temp_password_length)
        return(NX_SNMP_FAILED);

    /* Initialize MD5.  */
    _nx_md5_initialize(&MD);   

    /* Use while loop until we've done 1 Megabyte. */
    while (count < 1048576) 
    {
         
        cp = password_buf;
        for (i = 0; i < 64; i++) 
        {
        
            /* Take the next octet of the password, wrapping 
               to the beginning of the password as necessary.  */
            *cp++ = password[password_index++ % password_length];
         }
         _nx_md5_update(&MD, password_buf, 64);
         count += 64;
    }
    _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key);          /* tell MD5 we're done */

    /* Now localize the key with the engineID and pass   
       through MD5 to produce final key                  
       May want to ensure that engineLength <= 32,      
       otherwise need to use a buffer larger than 64  */
    if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32)
        return(NX_SNMP_FAILED);
    
    memcpy(password_buf, destination_key -> nx_snmp_security_key, 16);
    memcpy(password_buf+16, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size);
    memcpy(password_buf+16+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 16);

    _nx_md5_initialize(&MD);
    _nx_md5_update(&MD, password_buf, 32+agent_ptr -> nx_snmp_agent_v3_context_engine_size);
    _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key);

    /* Setup other information in the key structure.  */
    destination_key -> nx_snmp_security_key_type =   NX_SNMP_MD5_KEY;
    destination_key ->  nx_snmp_security_key_size =  16;

    /* Return successful completion to the caller.  */
    return(NX_SUCCESS);
#endif
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_privacy_key_use                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP privacy key             */ 
/*    specification function call. To disable encryption, set the         */
/*    key pointer to null.                                                */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Pointer to key to use for     */ 
/*                                            privacy (encryption)        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_privacy_key_use        Actual privacy key setup      */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
        return(NX_PTR_ERROR);

    if (key != NX_NULL)
    {

        /* Check for valid privacy key type. */
        if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY))
        {
            return NX_SNMP_INVALID_PDU_ENCRYPTION;
        }
    }

    /* Call actual service.  */
    status =  _nx_snmp_agent_privacy_key_use(agent_ptr, key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_privacy_key_use                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets up the specified key to use for privacy. To      */
/*    disable authentication, set the key pointer to null.                */
/*                                                                        */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Pointer to key to use for     */ 
/*                                            privacy (encryption)        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

#ifdef NX_SNMP_NO_SECURITY
    return NX_NOT_ENABLED;
#else


    /* Set the privacy pointer so encryption/decryption will use the specified key.  Note this
       key must have been created prior to calling this routine.  */
    agent_ptr -> nx_snmp_agent_v3_privacy_key =  key;

    /* Return success to the caller.  */
    return(NX_SUCCESS);
#endif
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_priv_trap_key_use                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for setting the privacy key   */
/*    for SNMPv3 trap messages.  To disable trap key encryption, set       */ 
/*    the key pointer to null.                                            */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Pointer to key to use for     */ 
/*                                            privacy (encryption)        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_priv_trap_key_use      Actual set privacy key for    */
/*                                           SNMPv3 trap messages service */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
    {
        return(NX_PTR_ERROR);
    }

    if (key != NX_NULL)
    {

        /* Check for valid privacy key type. */
        if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY))
        {
            return(NX_SNMP_INVALID_PDU_ENCRYPTION);
        }
    }

    /* Call actual service.  */
    status =  _nx_snmp_agent_priv_trap_key_use(agent_ptr, key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_priv_trap_key_use                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets up the specified key to use for privacy for      */
/*    sending SNMPv3 trap messages.                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    key                                   Pointer to key to use for     */ 
/*                                            privacy (encryption)        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key)
{

#ifdef NX_SNMP_NO_SECURITY
    return NX_NOT_ENABLED;
#else

    /* Set the privacy pointer so encryption/decryption will use the specified key.  Note this
       key must have been created prior to calling this routine.  */
    agent_ptr -> nx_snmp_agent_v3_priv_trap_key =  key;

    /* Return success to the caller.  */
    return(NX_SUCCESS);
#endif
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_sha_key_create                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP SHA key create          */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the SHA key      */ 
/*    destination_key                       Destination for the SHA key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_sha_key_create         Actual agent SHA key create   */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (password == NX_NULL) || (destination_key == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_sha_key_create(agent_ptr, password, destination_key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_sha_key_create                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function creates an SHA key.                                   */ 
/*                                                                        */ 
/*    Note: new API nx_snmp_agent_sha_key_create_extended is encouraged   */ 
/*    to use.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the SHA key      */ 
/*    destination_key                       Destination for the SHA key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_utility_string_length_check       Check string length           */ 
/*    _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create  */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key)
{

/* Verify SNMP security is not disabled for this project. */
#ifdef NX_SNMP_NO_SECURITY

    /* Security is not supported, clear the key and return an error.  */
    destination_key -> nx_snmp_security_key_type =   0;
    destination_key ->  nx_snmp_security_key_size =  0;

    /* Return an error.  */
    return(NX_NOT_ENABLED);
#else

UINT        status;
UINT        password_length;


    /* Calculate the password length.  */
    if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH))
    {
        return(NX_SIZE_ERROR);
    }

    /* Check length of password. */
    if (password_length == 0)
    {
        return(NX_SNMP_FAILED);
    }

    /* Call actual service.  */
    status = _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key);

    /* Return status.  */
    return(status);
#endif  /* NX_SNMP_NO_SECURITY */

}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_sha_key_create_extended             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP SHA key create          */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the SHA key      */ 
/*    password_length                       Length of password            */ 
/*    destination_key                       Destination for the SHA key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create  */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) ||
        (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_sha_key_create_extended              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function creates an SHA key.                                   */ 
/*                                                                        */ 
/*    Note: The string of password must be NULL-terminated and length     */
/*    of string matches the length specified in the argument list.        */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    password                              Password for the SHA key      */ 
/*    password_length                       Length of password            */ 
/*    destination_key                       Destination for the SHA key   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_sha1_initialize                   Initialize the SHA algorithm  */ 
/*    _nx_sha1_update                       SHA algorithm update          */ 
/*    _nx_sha1_digest_calculate             Calculate the SHA key         */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key)
{

/* Verify SNMP security is not disabled for this project. */
#ifdef NX_SNMP_NO_SECURITY

    /* Security is not supported, clear the key and return an error.  */
    destination_key -> nx_snmp_security_key_type =   0;
    destination_key ->  nx_snmp_security_key_size =  0;

    /* Return an error.  */
    return(NX_NOT_ENABLED);
#else

NX_SHA1     SH;
UCHAR      *cp, password_buf[72];
ULONG       password_index = 0;
ULONG       count = 0, i;
UINT        temp_password_length;


    /* Get the length of password string.  */
    if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length))
        return(NX_SNMP_FAILED);

    /* Check the password string length.  */
    if (password_length != temp_password_length)
        return(NX_SNMP_FAILED);

    memset(&SH, 0, sizeof(NX_SHA1));
    memset(&password_buf[0], 0, 72);  
    memset(destination_key, 0, sizeof(NX_SNMP_SECURITY_KEY));

    /* Initialize SHA.  */
    _nx_sha1_initialize(&SH);

    /* Use while loop until we've done 1 Megabyte.  */
    while (count < 1048576) 
    {
         
        cp = password_buf;
        for (i = 0; i < 64; i++) 
        {

            /* Take the next octet of the password, wrapping 
               to the beginning of the password as necessary.  */
             *cp++ = password[password_index++ % password_length];
         }
         _nx_sha1_update(&SH, password_buf, 64);
         count += 64;
    }
    _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key);          /* tell SHA we're done */

    /* Now localize the key with the engineID and pass 
       through SHA to produce final key                  
       May want to ensure that engineLength <= 32,
       otherwise need to use a buffer larger than 72.  */
    if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32)
        return(NX_SNMP_FAILED);

    memcpy(password_buf, destination_key -> nx_snmp_security_key, 20);
    memcpy(password_buf+20, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size);
    memcpy(password_buf+20+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 20);

    _nx_sha1_initialize(&SH);
    _nx_sha1_update(&SH, password_buf, 40+agent_ptr -> nx_snmp_agent_v3_context_engine_size);
    _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key);

    /* Setup other information in the key structure.  */
    destination_key -> nx_snmp_security_key_type =   NX_SNMP_SHA_KEY;
    destination_key ->  nx_snmp_security_key_size =  20;

    /* Return successful completion to the caller.  */
    return(NX_SUCCESS);
#endif  /* NX_SNMP_NO_SECURITY */

}
#endif /* NX_SNMP_DISABLE_V3 */


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_public_string_test                  PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for the check of community    */
/*    string against the agent's public community string.                 */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to public string      */ 
/*    is_public                             Pointer to outcome            */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agents_public_string_test    Check public string service   */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public)
{

UINT status;

    if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_public == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_public_string_test(agent_ptr, community_string, is_public);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_public_string_test                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs checks the input community string against the*/
/*    agent's public community string.                                    */
/*                                                                        */ 
/*    Note: The string length of community_string is limited by           */ 
/*    NX_SNMP_MAX_USER_NAME.                                              */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to public string      */ 
/*    is_public                             Pointer to outcome            */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public)
{
UINT string_length1, string_length2;


    if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME))
    {
        return(NX_SIZE_ERROR);
    }

    if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_public_community_string, &string_length2, NX_SNMP_MAX_USER_NAME))
    {
        return(NX_SIZE_ERROR);
    }

    /* Initialize the outcome */
    *is_public = NX_TRUE;

    if (string_length1 != string_length2)
    {
        /* Input string not the same as agent's public string. */
        *is_public = NX_FALSE;
        return(NX_SUCCESS);
    }

    /* The string lengths match, now match the actual strings. */
    if (memcmp(community_string, agent_ptr -> nx_snmp_agent_public_community_string, string_length1))
    {

        /* Input string not the same as agent's public string. */
        *is_public = NX_FALSE;
    }

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_private_string_test                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for the nx_snmp_agent_receive_*/ 
/*    _private_string service.                                            */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to received string    */ 
/*    is_private                            Pointer to outcome            */ 
/*                                             NX_TRUE if strings match   */
/*                                             NX_FALSE if strings do not */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_private_string_test                                  */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private)
{

UINT status;

    if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_private == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_private_string_test(agent_ptr, community_string, is_private);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_private_string_test                  PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function determines if the community string of the received    */
/*    SNMP packet matches the SNMP agent's private community string.      */ 
/*                                                                        */ 
/*    Note: The string length of community_string is limited by           */ 
/*    NX_SNMP_MAX_USER_NAME.                                              */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to received string    */ 
/*    is_private                            Pointer to outcome            */ 
/*                                             NX_TRUE if strings match   */
/*                                             NX_FALSE if strings do not */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private)
{
UINT string_length1, string_length2;

    if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME))
    {
        return(NX_SIZE_ERROR);
    }

    if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_private_community_string, &string_length2, NX_SNMP_MAX_USER_NAME))
    {
        return(NX_SIZE_ERROR);
    }

    /* Initialize the outcome */
    *is_private = NX_TRUE;

    if (string_length1 != string_length2)
    {
        /* Input string not the same as agent's private string. */
        *is_private = NX_FALSE;
        return(NX_SUCCESS);
    }

    /* The string lengths match, now match the actual strings. */
    if (memcmp(community_string, agent_ptr -> nx_snmp_agent_private_community_string, string_length1))
    {

        /* Input string not the same as agent's private string. */
        *is_private = NX_FALSE;
    }

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_private_string_set                  PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for the nx_snmp_agent_set_    */ 
/*    _private_string service.                                            */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to private string     */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_private_string_set     Set private string service    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string)
{

UINT status;

    /* Check for invalid pointer input. */
    if ((agent_ptr == NX_NULL) || (community_string == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    /* Call the actual service. */
    status = _nx_snmp_agent_private_string_set(agent_ptr, community_string);


    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_private_string_set                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the input string and size input as the Agent's   */
/*    private string and private string size.                             */
/*                                                                        */ 
/*    Note: The string length of community_string is limited by           */ 
/*    NX_SNMP_MAX_USER_NAME.                                              */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to private string     */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string)
{

UINT i;
UINT length;


    /* Verify the string is not too large, leaving room for the null terminating string. */
    if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME))
    {
        return NX_SNMP_ERROR_TOOBIG;
    }

    /* Copy the string to the SNMP agent private community string. */
    for (i = 0; i < length; i++)
    {
        agent_ptr -> nx_snmp_agent_private_community_string[i] = *community_string;
        community_string++;
    }

    /* Null terminate the string. */
    agent_ptr -> nx_snmp_agent_private_community_string[i] = 0x0;

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_public_string_set                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function performs error checking for the nx_snmp_agent_set_    */ 
/*    _public_string service.                                             */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to public string      */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_public_string_set      Set public string service     */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nxe_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string)
{

UINT status;

    if ((agent_ptr == NX_NULL) || (community_string == NX_NULL))
    {
        return NX_PTR_ERROR;
    }

    status = _nx_snmp_agent_public_string_set(agent_ptr, community_string);

    return status;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_public_string_set                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sets the input string and size input as the Agent's   */
/*    public string and public string size.                               */
/*                                                                        */ 
/*    Note: The string length of community_string is limited by           */ 
/*    NX_SNMP_MAX_USER_NAME.                                              */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    community_string                      Pointer to public  string     */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successful completion status  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string)
{
UINT i;
UINT length;


    /* Verify the string is not too large, leaving room for the null terminating character. */
    if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME))
    {
        return NX_SNMP_ERROR_TOOBIG;
    }

    /* Copy the string to the SNMP agent public community string. */
    for (i = 0; i < length; i++)
    {
        agent_ptr -> nx_snmp_agent_public_community_string[i] = *community_string;
        community_string++;
    }

    /* Null terminate the string. */
    agent_ptr -> nx_snmp_agent_public_community_string[i] = 0x0;

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_start                               PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent start             */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_start                  Actual agent start function   */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_start(NX_SNMP_AGENT *agent_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_start(agent_ptr);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_start                                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function starts the SNMP agent thread.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    tx_thread_resume                      Resume SNMP agent thread      */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr)
{

UINT status;

    /* Bind the socket to a the well known SNMP UDP port number.  */
    status =  nx_udp_socket_bind(&(agent_ptr -> nx_snmp_agent_socket), NX_SNMP_AGENT_PORT, NX_NO_WAIT);

    /* Determine if an error occurred.  */
    if (status)
    {

        /* Delete the UDP socket.  */
        nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket));

        /* Yes, return error code.  */
        return(NX_SNMP_ERROR);
    }

    /* Start the SNMP agent thread.  */
    tx_thread_resume(&(agent_ptr -> nx_snmp_agent_thread));


    /* Return successful status.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_stop                                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent stop              */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_stop                   Actual agent stop function    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_stop(agent_ptr);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_stop                                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function stops the SNMP agent thread.                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    tx_thread_suspend                     Suspend SNMP agent thread     */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr)
{

    /* Stop the SNMP agent thread.  */
    tx_thread_suspend(&(agent_ptr -> nx_snmp_agent_thread));

    /* Unbind the UDP socket.  */
    nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket));

    /* Return successful status.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function is the entry function of the SNMP agent thread.       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    snmp_agent_address                    Pointer to SNMP agent         */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_copy                        Copy SNMP packet              */ 
/*    nx_packet_release                     Release original SNMP packet  */ 
/*    _nx_snmp_utility_sequence_get         Get sequence number in packet */ 
/*    _nx_snmp_utility_version_get          Get SNMP version number       */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*    nx_udp_socket_receive                 Receive SNMP request          */ 
/*    nx_udp_source_extract                 Extract source IP and port    */ 
/*                                            from request                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    ThreadX                                                             */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_agent_thread_entry(ULONG snmp_agent_address)
{

NX_SNMP_AGENT           *agent_ptr;
UCHAR                   *buffer_ptr;
NX_PACKET               *packet_ptr;
UINT                    length;
UINT                    version;
UINT                    status;
UINT                    sequence_length;
INT                     buffer_length;
NX_PACKET               *new_packet_ptr;


    /* Setup the agent pointer.  */
    agent_ptr =  (NX_SNMP_AGENT *) snmp_agent_address; 

    /* Loop to process SNMP Manager requests.  */
    while(1)
    {

        /* Wait for a SNMP Manager request.  */    
        status =  nx_udp_socket_receive(&(agent_ptr -> nx_snmp_agent_socket), &packet_ptr, NX_WAIT_FOREVER);  

        /* Check for a successful packet reception.  */
        if (status)
        {

            /* If the error is other than no packet received, update the internal error count. */
            if (status != NX_NO_PACKET)
            {
                /* Increment the internal error counter.  */
                agent_ptr -> nx_snmp_agent_internal_errors++;
            }

            /* Go back and wait for another packet.  */
            continue;
        }


        /* Pickup the source information for the packet - do this before the packet copy since the information
           prior to the prepend pointer is not copied!  */
        nx_udp_source_extract(packet_ptr, &agent_ptr -> nx_snmp_agent_current_manager_ip, 
                              &(agent_ptr -> nx_snmp_agent_current_manager_port));

        /* Determine if we have to copy the packet into a packet from the SNMP pool.  */
        if (packet_ptr -> nx_packet_next)
        {

            /* Copy the packet into a packet from the SNMP pool.  */
            status =  nx_packet_copy(packet_ptr, &new_packet_ptr, agent_ptr -> nx_snmp_agent_packet_pool_ptr, NX_SNMP_AGENT_TIMEOUT);

            /* Release the original packet.  */
            nx_packet_release(packet_ptr);

            /* Determine if the copy was successful.  */
            if (status || (new_packet_ptr -> nx_packet_next != NX_NULL))
            {

                /* No, the packet copy was not successful.  */

                /* Increment the internal error counter.  */
                agent_ptr -> nx_snmp_agent_internal_errors++;

                /* Go back and wait for another packet.  */
                continue;
            }

            /* Otherwise, copy the new packet pointer to the standard packet pointer.  */
            packet_ptr =  new_packet_ptr;
        }


        buffer_length = (INT)(packet_ptr -> nx_packet_length);

        /* Setup a pointer to the buffer.  */
        buffer_ptr =  packet_ptr -> nx_packet_prepend_ptr;

        /* Pickup the SEQUENCE field.  */
        length =  _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the unknown command error.  */
            agent_ptr -> nx_snmp_agent_unknown_requests++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Go back and wait for another packet.  */
            continue;
        }

        /* Move the buffer pointer up.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /* Pickup the SNMP VERSION field.  */
        length =  _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the unknown command error.  */
            agent_ptr -> nx_snmp_agent_unknown_requests++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Go back and wait for another packet.  */
            continue;
        }

        /* Increment the total number of packets received.  */
        agent_ptr -> nx_snmp_agent_packets_received++;

        /* We have a valid SNMP version, process relative to the type of SNMP version.  */
        if (version == NX_SNMP_VERSION_1)
        {

#ifndef NX_SNMP_DISABLE_V1
            /* Verify V1 is currently enabled for this agent. */
            if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE)
            {

                /* It is not. Increment error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_version++;

                /* Release packet.  */
                nx_packet_release(packet_ptr);
            }
            else
            {

                /* Update the SNMP agent's version. */
                agent_ptr -> nx_snmp_agent_current_version = version;

                /* Process SNMP Version 1 request.  */
                _nx_snmp_version_1_process(agent_ptr, packet_ptr);
            }
#else


            /* Invalid version. Increment error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_version++;

            /* Release packet.  */
            nx_packet_release(packet_ptr);
#endif
        }
#ifdef NX_SNMP_V2C_ONLY
        else if (version == NX_SNMP_VERSION_2C)
#else
        else if ((version == NX_SNMP_VERSION_2) || (version == NX_SNMP_VERSION_2C))
#endif
        {

#ifndef NX_SNMP_DISABLE_V2

            /* Verify V2 is currently enabled for this agent. */
            if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE)
            {
                /* It is not. Increment error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_version++;

                /* Release packet.  */
                nx_packet_release(packet_ptr);
            }
            else
            {
                /* Update the SNMP agent's version. */
                agent_ptr -> nx_snmp_agent_current_version = version;


                /* Process SNMP Version 2 request.  */
                _nx_snmp_version_2_process(agent_ptr, packet_ptr);
            }
#else

            /* Invalid version. Increment error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_version++;

            /* Release packet.  */
            nx_packet_release(packet_ptr);
#endif
        }
        else if (version == NX_SNMP_VERSION_3)
        {

#ifndef NX_SNMP_DISABLE_V3

            /* Verify V3 is currently enabled for this agent. */
            if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE)
            {

                /* It is not. Increment error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_version++;

                /* Release packet.  */
                nx_packet_release(packet_ptr);
            }
            else
            {
                /* Update the SNMP agent's version. */
                agent_ptr -> nx_snmp_agent_current_version = version;

                /* Process SNMP Version 3 request.  */
                _nx_snmp_version_3_process(agent_ptr, packet_ptr);
            }
#else

            /* Invalid version. Increment error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_version++;

            /* Release packet.  */
            nx_packet_release(packet_ptr);
#endif
        }
        else
        {

            /* Invalid version. Increment error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_version++;

            /* Release packet.  */
            nx_packet_release(packet_ptr);
        }
    }
}


#ifndef NX_SNMP_DISABLE_V1
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_trap_send                           PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMPv1 trap send service.    */
/*                                                                        */
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IPv4 address      */ 
/*    community                             Community string              */ 
/*    enterprise                            Identifies the device that is */ 
/*                                            generating the trap         */ 
/*    trap_type                             Type of trap                  */ 
/*    trap_code                             Additional trap information   */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Actual agent trap send        */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, 
                                UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL) || (enterprise == NX_NULL))
        return(NX_PTR_ERROR);

    /* Check for invalid IP address.  */
    if (ip_address == 0)
        return(NX_IP_ADDRESS_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_trap_send(agent_ptr, ip_address, community, enterprise, trap_type, trap_code, elapsed_time, object_list_ptr);

    /* Return status.  */
    return(status);
}




/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send                            PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function builds and sends a SNMP v1 trap message to the input  */ 
/*    destination address.                                                */
/*                                                                        */ 
/*    Note: The string length of community and enterprise are limited by  */ 
/*    the packet payload and NX_SNMP_MAX_USER_NAME.                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IP address        */ 
/*    community                             Community string              */ 
/*    enterprise                            Identifies the device that is */ 
/*                                            generating the trap         */ 
/*    trap_type                             Type of trap                  */ 
/*    trap_code                             Additional trap information   */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_allocate                    Allocate SNMP trap packet     */
/*    nx_packet_release                     Release SNMP packet           */ 
/*    nx_udp_socket_send                    Send SNMP trap via UDP        */ 
/*    _nx_snmp_object_copy                  Copy object                   */ 
/*    _nx_snmp_utility_community_set        Set the community name        */ 
/*    _nx_snmp_utility_object_data_set      Set the data value            */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_sequence_set         Set the ASN.1 sequence        */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_version_set          Set the SNMP v1               */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, 
                               UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT                 status;
UINT                 trap_length;
UCHAR                *trap_object_ptr;
NX_SNMP_OBJECT_DATA  *trap_object_data_ptr = NX_NULL;
NX_SNMP_OBJECT_DATA  trap_object_data;
NX_PACKET            *trap_packet_ptr;
UCHAR                *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr;
UINT                 trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length;
UINT                 packet_type;


    /* Verify V1 is currently enabled for this agent. */
    if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE)
    {

        return NX_NOT_ENABLED;
    }

    /* Now prepare trap message so we can process the variables one by one.  */

    packet_type = NX_UDP_PACKET;

    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a trap packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the trap packet.  */
    trap_sequence_length =       0; 
    trap_type_length =           0;
    trap_variable_list_length =  0;

    /* Setup a pointer to the trap packet's buffer area.  */
    trap_buffer_ptr =  trap_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the trap sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the trap.  */
    trap_sequence_ptr =  trap_buffer_ptr;

    /* First, write the sequence in the trap packet.  A zero is written for now.  This will be 
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Now set the Version ID in the trap message.  */
    trap_length =  _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_1, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the community in the trap message.  */
    trap_length =  _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Remember the request type pointer, since it will need to be updated later.  */
    trap_type_ptr =  trap_buffer_ptr;

    /* Now set the request type in the trap message.  */
    trap_length =  _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the enterprise ID in the trap message.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, enterprise, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the agent's IP address.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_IP_ADDRESS;


    trap_object_data.nx_snmp_object_data_msw =   
        (LONG)(agent_ptr -> nx_snmp_agent_ip_ptr) -> nx_ip_interface[agent_ptr -> nx_snmp_agent_interface_index].nx_interface_ip_address;

    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Check that we have a valid trap type requested.  */
    if (trap_type > TRAP_ID_MAX)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Set the trap type.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_INTEGER;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)trap_type;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    if (trap_length == 0)
    {
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the specific trap type.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_INTEGER;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)trap_code;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the specific time-stamp.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_TIME_TICS;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)elapsed_time;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the trap's variable list field.  */
    trap_variable_list_ptr =  trap_buffer_ptr;

    /* Set up the variable list.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Default the object pointer to NULL.  */
    trap_object_ptr =  NX_NULL;

    /* Determine if an object is specified.  */
    if (object_list_ptr)
    {

        /* Setup object pointers from the supplied object list.  */
        trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
        trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

        /* Check for a valid operation.  */
        if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
        {
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    }

    /* Loop to process all the objects in the list.  */
    while (trap_object_ptr)
    {

        /* Clear the trap variable length.  */
        trap_variable_length =  0;

        /* Remember the start of the variable.  */
        trap_variable_ptr =  trap_buffer_ptr;

        /* Setup the variable trap sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the trap packet too.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the object into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Insert the object's data into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Now update the trap variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Default the object pointer to NULL.  */
        trap_object_ptr =  NX_NULL;

        /* Determine if there are more objects to insert into the trap message.  */
        if (object_list_ptr)
        {

            /* Move to the next object in the list.  */
            object_list_ptr++;

            if (object_list_ptr == NX_NULL)
            {

                /* Release the trap packet.  */
                nx_packet_release(trap_packet_ptr);

                /* Done, return to caller.  */
                return(NX_SNMP_ERROR);
            }

            /* Determine if there is another object.  */
            if (object_list_ptr -> nx_snmp_object_string_ptr)
            {

                /* Setup the object and object data pointers.  */
                trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
                trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

                /* Check for a valid operation.  */
                if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
                {
                    /* Release the trap packet.  */
                    nx_packet_release(trap_packet_ptr);

                    /* Done, return to caller.  */
                    return(NX_SNMP_ERROR);
                }
            }
        }
    } 

    /* At this point, several trap fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end);

    /* Now the trap packet's pointers must be setup so it can be sent.  */
    trap_packet_ptr -> nx_packet_length =  (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr);
    trap_packet_ptr -> nx_packet_append_ptr =  trap_buffer_ptr;

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_traps_sent++;
    agent_ptr -> nx_snmp_agent_packets_sent++;

    /* Send the trap packet back to the requesting SNMP manager.  */
    status = nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, 
                                               ip_address, NX_SNMP_MANAGER_TRAP_PORT);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(trap_packet_ptr);
    }

    /* Return completion status.  */
    return(status);
}
#endif /* NX_SNMP_DISABLE_V1 */


#ifndef NX_SNMP_DISABLE_V2
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_trapv2_send                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMPv2 trap send service.    */
/*                                                                        */
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IPv4 address      */ 
/*    community                             Community name                */ 
/*    trap_type                             Type of trap                  */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv2_send            Actual NetX (IPv4) SNMP trap  */ 
/*                                            send service                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || 
        (community == NX_NULL) || (ip_address == 0))
        return(NX_PTR_ERROR);

    /* Call actual netx service.  */
    status =  _nx_snmp_agent_trapv2_send(agent_ptr, ip_address, community, trap_type, elapsed_time, object_list_ptr);

    /* Return status.  */
    return(status);
}




/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv2_send                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function builds and sends a SNMPv2 trap message to the input   */ 
/*    destination address.                                                */
/*                                                                        */ 
/*    Note: The string length of community is limited by the packet       */ 
/*    payload and NX_SNMP_MAX_USER_NAME.                                  */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IP address        */ 
/*    community                             Community name                */ 
/*    trap_type                             Type of trap                  */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_allocate                    Allocate SNMP trap packet     */
/*    nx_packet_release                     Release SNMP packet           */ 
/*    nx_udp_socket_send                    Send SNMP trap via UDP        */ 
/*    _nx_snmp_object_copy                  Copy object                   */ 
/*    _nx_snmp_utility_community_set        Set the community name        */ 
/*    _nx_snmp_utility_error_info_set       Set error information         */ 
/*    _nx_snmp_utility_object_data_set      Set the data value            */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_sequence_set         Set the ASN.1 sequence        */ 
/*    _nx_snmp_utility_request_id_set       Set the Trap ID               */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_version_set          Set the SNMP v1               */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type,  
                                 ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT                 status;
UINT                 trap_length;
UCHAR                *trap_object_ptr;
NX_SNMP_OBJECT_DATA  trap_object_data;
NX_SNMP_OBJECT_DATA  *trap_object_data_ptr = NX_NULL;
NX_PACKET            *trap_packet_ptr;
UCHAR                *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr;
UINT                 trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length;
UINT                 packet_type;


    /* Verify V2 is currently enabled for this agent. */
    if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE)
    {
        return NX_NOT_ENABLED;
    }

    packet_type = NX_UDP_PACKET;

    /* Now prepare trap message so we can process the variables one by one.  */

    /* Allocate the packet for the SNMP v2 trap.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a trap packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the trap packet.  */
    trap_sequence_length =       0; 
    trap_type_length =           0;
    trap_variable_list_length =  0;
    trap_variable_length =       0;

    /* Setup a pointer to the trap packet's buffer area.  */
    trap_buffer_ptr =  trap_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the trap sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the trap.  */
    trap_sequence_ptr =  trap_buffer_ptr;

    /* First, write the sequence in the trap packet.  A zero is written for now.  This will be 
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Now set the Version ID in the trap message.  */
    trap_length =  _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the community in the trap message.  */
    trap_length =  _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Remember the request type pointer, since it will need to be updated later.  */
    trap_type_ptr =  trap_buffer_ptr;

    /* Now set the request type in the trap message.  */
    trap_length =  _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the trap ID in the trap message.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;


    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the trap error information.  */
    trap_length =  _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the trap's variable list field.  */
    trap_variable_list_ptr =  trap_buffer_ptr;

    /* Setup the variable list.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Setup the variable trap sequence.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Place the sysUpTime object ID into the trap buffer.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", 
                                                  trap_packet_ptr -> nx_packet_data_end); 

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Insert the SysTimerTicks into the trap buffer as the first item in the variable binding list.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_TIME_TICS;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)elapsed_time;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Clear the trap variable size.  */
    trap_variable_length =  0;

    /* Check that we have a valid trap type requested.  */
    if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM))
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Check that we have a trap list if a custom trap is requested.  */
    if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM))
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Check if this is an enumerated trap event. */
    if (trap_type <= TRAP_ID_MAX)
    {

        /* Set up the variable trap sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;
    
            /* Release the trap packet too.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the snmpTrapOID object ID into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", 
                                                      trap_packet_ptr -> nx_packet_data_end); 
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;
    
        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;
    
        /* Set an Object ID for the data.  */
        trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_OBJECT_ID;
        trap_object_data.nx_snmp_object_data_msw =   0;

        /* Copy the object specified by the trap_type index. */
        _nx_snmp_object_copy(_nx_snmp_v2_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string);
    
        /* Add trap object data to trap buffer. */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;
    
        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;
    }

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Default the object pointer to NULL.  */
    trap_object_ptr =  NX_NULL;

    /* Determine if an object is specified.  */
    if (object_list_ptr)
    {

        /* Setup object pointers from the supplied object list.  */
        trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
        trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

        /* Check for a valid operation.  */
        if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
        {
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    }

    /* Loop to process all the objects in the list.  */
    while (trap_object_ptr)
    {

        /* Clear the trap variable length.  */
        trap_variable_length =  0;

        /* Remember the start of the variable.  */
        trap_variable_ptr =  trap_buffer_ptr;

        /* Setup the variable trap sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the trap packet too.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the object into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Insert the object's data into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Now update the trap variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Default the object pointer to NULL.  */
        trap_object_ptr =  NX_NULL;

        /* Determine if there are more objects to insert into the trap message.  */
        if (object_list_ptr)
        {

            /* Move to the next object in the list.  */
            object_list_ptr++;

            if (object_list_ptr == NX_NULL)
            {
                /* Release the trap packet.  */
                nx_packet_release(trap_packet_ptr);

                /* Done, return to caller.  */
                return(NX_SNMP_ERROR);
            }

            /* Determine if there is another object.  */
            if (object_list_ptr -> nx_snmp_object_string_ptr)
            {

                /* Setup the object and object data pointers.  */
                trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
                trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

                /* Check for a valid operation.  */
                if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
                {
                    /* Release the trap packet.  */
                    nx_packet_release(trap_packet_ptr);

                    /* Done, return to caller.  */
                    return(NX_SNMP_ERROR);
                }
            }
        }
    } 

    /* At this point, several trap fields need to be updated with actual lengths.  */

    _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); 
    _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end);

    /* Update the trap packet's pointers.  */
    trap_packet_ptr -> nx_packet_length =  (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr);
    trap_packet_ptr -> nx_packet_append_ptr =  trap_buffer_ptr;

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_traps_sent++;
    agent_ptr -> nx_snmp_agent_packets_sent++;

    /* Send the trap packet back to the requesting SNMP manager.  */
    status = nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, 
                                 ip_address, NX_SNMP_MANAGER_TRAP_PORT);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return an error.  */
        return(NX_SNMP_ERROR);
    }

    /* Return completion status.  */
    return(NX_SUCCESS);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nxe_snmp_agent_trapv2_oid_send                     PORTABLE C      */
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function checks for errors in the SNMP agent v2 trap send      */
/*    function call.                                                      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    agent_ptr                             Pointer to SNMP agent         */
/*    ip_address                            Destination IP address        */
/*    community                             Community name                */
/*    OID                                   OID to send                   */
/*    elapsed_time                          Elapsed time from last boot   */
/*                                            of the device (sysUpTime)   */
/*    object_list_ptr                       Variable list of application  */
/*                                            objects to present with the */
/*                                            trap                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_snmp_agent_trapv2_oid_send        Actual agent trap send        */
/*                                            function                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL))
        return(NX_PTR_ERROR);

    /* Check for invalid IP address.  */
    if (ip_address == 0)
        return(NX_IP_ADDRESS_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_trapv2_oid_send(agent_ptr, ip_address, community, oid, elapsed_time, object_list_ptr);

    /* Return status.  */
    return(status);
}



/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_snmp_agent_trapv2_oid_send                      PORTABLE C      */
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function builds and sends a SNMP v2 trap message using the OID */
/*    directly from the caller.                                           */
/*                                                                        */ 
/*    Note: The string length of community is limited by the packet       */ 
/*    payload and NX_SNMP_MAX_USER_NAME. The string length of oid is      */ 
/*    limited by the packet payload and NX_SNMP_MAX_OCTET_STRING.         */ 
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    agent_ptr                             Pointer to SNMP agent         */
/*    ip_address                            Destination IP address        */
/*    community                             Community name                */
/*    OID                                   OID to send                   */
/*    elapsed_time                          Elapsed time from last boot   */
/*                                            of the device (sysUpTime)   */
/*    object_list_ptr                       Variable list of application  */
/*                                            objects to present with the */
/*                                            trap                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    nx_packet_allocate                    Allocate SNMP trap packet     */
/*    nx_packet_release                     Release SNMP packet           */
/*    nx_udp_socket_send                    Send SNMP trap via UDP        */
/*    _nx_snmp_object_copy                  Copy object                   */
/*    _nx_snmp_utility_community_set        Set the community name        */
/*    _nx_snmp_utility_error_info_set       Set error information         */
/*    _nx_snmp_utility_object_data_set      Set the data value            */
/*    _nx_snmp_utility_object_id_set        Set the object ID             */
/*    _nx_snmp_utility_sequence_set         Set the ASN.1 sequence        */
/*    _nx_snmp_utility_request_id_set       Set the Trap ID               */
/*    _nx_snmp_utility_sequence_set_1byte                                 */
/*                                          Set trap sequence             */
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_version_set          Set the SNMP v1               */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT                 status;
UINT                 trap_length;
UCHAR                *trap_object_ptr;
NX_SNMP_OBJECT_DATA  trap_object_data;
NX_SNMP_OBJECT_DATA  *trap_object_data_ptr = NX_NULL;
NX_PACKET            *trap_packet_ptr;
UCHAR                *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr;
UINT                 trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length;
UINT                 packet_type = NX_UDP_PACKET;



    /* Allocate the packet for the SNMP v2 trap.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a trap packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Now prepare trap message so we can process the variables one by one.  */

    /* Initialize the counters required for the length fields of the trap packet.  */
    trap_sequence_length =       0;
    trap_type_length =           0;
    trap_variable_list_length =  0;
    trap_variable_length =       0;

    /* Setup a pointer to the trap packet's buffer area.  */
    trap_buffer_ptr =  trap_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the trap sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the trap.  */
    trap_sequence_ptr =  trap_buffer_ptr;

    /* First, write the sequence in the trap packet.  A zero is written for now.  This will be
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Now set the Version ID in the trap message.  */
    trap_length =  _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the community in the trap message.  */
    trap_length =  _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Remember the request type pointer, since it will need to be updated later.  */
    trap_type_ptr =  trap_buffer_ptr;

    /* Now set the request type in the trap message.  */
    trap_length =  _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now set the trap ID in the trap message.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the trap error information.  */
    trap_length =  _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the trap's variable list field.  */
    trap_variable_list_ptr =  trap_buffer_ptr;

    /* Setup the variable list.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Setup the variable trap sequence.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Place the sysUpTime object ID into the trap buffer.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Insert the object's data into the trap buffer.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_TIME_TICS;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)elapsed_time;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Clear the trap variable size.  */
    trap_variable_length =  0;

    /* Setup the variable trap sequence.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Place the snmpTrapOID object ID into the trap buffer.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Set a Object ID for the data.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_OBJECT_ID;
    trap_object_data.nx_snmp_object_data_msw =   0;

    /* Check oid length.  */
    if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING))
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string);
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Default the object pointer to NULL.  */
    trap_object_ptr =  NX_NULL;

    /* Determine if an object is specified.  */
    if (object_list_ptr)
    {

        /* Setup object pointers from the supplied object list.  */
        trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
        trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

        /* Check for a valid operation.  */
        if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
        {
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    }

    /* Loop to process all the objects in the list.  */
    while (trap_object_ptr)
    {

        /* Clear the trap variable length.  */
        trap_variable_length =  0;

        /* Remember the start of the variable.  */
        trap_variable_ptr =  trap_buffer_ptr;

        /* Setup the variable trap sequence.  For now, the length will be zero.  We
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the trap packet too.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the object into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Insert the object's data into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Now update the trap variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Default the object pointer to NULL.  */
        trap_object_ptr =  NX_NULL;

        /* Determine if there are more objects to insert into the trap message.  */
        if (object_list_ptr)
        {

            /* Move to the next object in the list.  */
            object_list_ptr++;

            if (object_list_ptr == NX_NULL)
            {
                /* Release the trap packet.  */
                nx_packet_release(trap_packet_ptr);

                /* Done, return to caller.  */
                return(NX_SNMP_ERROR);
            }

            /* Determine if there is another object.  */
            if (object_list_ptr -> nx_snmp_object_string_ptr)
            {

                /* Setup the object and object data pointers.  */
                trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
                trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

                /* Check for a valid operation.  */
                if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
                {
                    /* Release the trap packet.  */
                    nx_packet_release(trap_packet_ptr);

                    /* Done, return to caller.  */
                    return(NX_SNMP_ERROR);
                }
            }
        }
    }

    /* At this point, several trap fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end);

    /* Now the trap packet's pointers must be setup so it can be sent.  */
    trap_packet_ptr -> nx_packet_length =  (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr);
    trap_packet_ptr -> nx_packet_append_ptr =  trap_buffer_ptr;

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_traps_sent++;
    agent_ptr -> nx_snmp_agent_packets_sent++;


    /* Send the trap packet back to the requesting SNMP manager. */

    status = nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ip_address, NX_SNMP_MANAGER_TRAP_PORT);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return an error.  */
        return(NX_SNMP_ERROR);
    }

    /* Return completion status.  */
    return(NX_SUCCESS);
}


#endif /* NX_SNMP_DISABLE_V2 */


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_agent_trapv3_send                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the NetX (IPv4) SNMP agent v3    */ 
/*    trap send service.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IPv4 address      */ 
/*    username                              Username                      */ 
/*    trap_type                             Type of trap                  */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv3_send            Actual NetX (IPv4) SNMP agent */ 
/*                                            trap send service           */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, 
                                  ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) 
        || (username == NX_NULL) || (ip_address == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_trapv3_send(agent_ptr, ip_address, username, trap_type, elapsed_time, object_list_ptr);

    /* Return status.  */
    return(status);
}



/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv3_send                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function builds and sends a SNMP v3 trap message to the input  */ 
/*    destination address.                                                */
/*                                                                        */ 
/*    Note: The string length of username is limited by the packet        */ 
/*    payload and NX_SNMP_MAX_OCTET_STRING.                               */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    ip_address                            Destination IP address        */ 
/*    username                              Username                      */ 
/*    trap_type                             Type of trap                  */ 
/*    elapsed_time                          Elapsed time from last boot   */ 
/*                                            of the device (sysUpTime)   */ 
/*    object_list_ptr                       Variable list of application  */ 
/*                                            objects to present with the */ 
/*                                            trap                        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_des_key_set                       Setup DES encryption          */ 
/*    _nx_des_encrypt                       Encrypt bytes                 */ 
/*    _nx_md5_digest_calculate              MD5 algorithm completion      */ 
/*    _nx_md5_initialize                    MD5 algorithm initialization  */ 
/*    _nx_md5_update                        MD5 algorithm computation     */ 
/*    nx_packet_allocate                    Allocate SNMP trap packet     */
/*    nx_packet_release                     Release SNMP packet           */ 
/*    nx_udp_socket_send                    Send SNMP trap via UDP        */ 
/*    _nx_snmp_object_copy                  Copy object                   */ 
/*    _nx_snmp_utility_error_info_set       Set error information         */ 
/*    _nx_snmp_utility_octet_set            Set octet string              */
/*    _nx_snmp_utility_object_data_set      Set the data value            */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_sequence_set         Set the ASN.1 sequence        */ 
/*    _nx_snmp_utility_request_id_set       Set the Request ID            */ 
/*    _nx_snmp_utility_request_type_set_1byte  Set trap request type      */
/*    _nx_snmp_utility_version_set          Set the SNMP v3               */ 
/*    _nx_sha1_digest_calculate             SHA algorithm completion      */ 
/*    _nx_sha1_initialize                   SHA algorithm initialization  */ 
/*    _nx_sha1_update                       SHA algorithm computation     */ 
/*    tx_time_get                           Get time                      */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, 
                                 NX_SNMP_TRAP_OBJECT *object_list_ptr)
{
           
UINT                 status;
UINT                 trap_length;
UCHAR                *trap_object_ptr;
NX_SNMP_OBJECT_DATA  trap_object_data;
NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL;
NX_PACKET           *trap_packet_ptr;
UCHAR               *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr;
UINT                 trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length;
UCHAR                temp_string[NX_SNMP_DIGEST_SIZE];
UINT                 i;
UCHAR               *temp_ptr;
UINT                j, padding;
UCHAR               *trap_encryption_size_ptr = NX_NULL;
UCHAR               *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL;
UCHAR               key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR               key2[NX_SNMP_DIGEST_WORKING_SIZE];
UINT                packet_type;
UCHAR               message_security_options = 0;
UINT                username_length;


    /* Verify V3 is currently enabled for this agent. */
    if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE)
    {

        return NX_NOT_ENABLED;
    }

    packet_type = NX_UDP_PACKET;

    /* Allocate the packet for the SNMP response.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a trap packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the trap packet.  */
    trap_sequence_length =       0; 
    trap_header_length =         0;
    trap_security_length =       0;
    trap_pdu_length =            0;
    trap_type_length =           0;
    trap_variable_list_length =  0;
    trap_variable_length =       0;

    /* Setup a pointer to the trap packet's buffer area.  */
    trap_buffer_ptr =  trap_packet_ptr -> nx_packet_prepend_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap buffer response at 0x%x\n", trap_buffer_ptr);
#endif
    /* This is also the trap sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the response.  */
    trap_sequence_ptr =  trap_buffer_ptr;

    /* First, write the sequence in the trap packet.  A zero is written for now.  This will be 
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;


    /* Now set the Version ID in the trap message.  */
    trap_length =  _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Save the pointer to the global header.  */
    trap_header_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap3 header header at 0x%x\n", trap_header_ptr);
#endif

    /* Write the sequence for the global header in the trap packet.  A zero is written for now.  
       This will be updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /***************8 Now set the request ID.  *********************8*/
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /********************* Now set the maximum message size.  ***************************8*/
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /********************** Now set the security options e.g. Flags.  ****************************/

    /* Determine what the trap message security options are. These are not the same as
       the general get/set request PDU options.  */
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)
    {
        message_security_options = NX_SNMP_SECURITY_AUTHORIZE;
    }
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {
        message_security_options |= NX_SNMP_SECURITY_PRIVACY;
    }

    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /******************* Now set the security type (always USM model).  *********************/
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /* At this point, we have successfully built the security header.  */


    /************************** Start the security parameters field. ************************/

    /* First set up the octet string field. For now just put in zeros... we will update when 
      the actual size is known.  */  
    trap_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
    trap_buffer_ptr[1] =  0;

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + 2;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + 2;

    /* Remember the security header length pointer.  */
    trap_security_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap3 security header 0x%x\n", trap_security_ptr);
#endif
    /* Now set the sequence of the USM security parameters.  */
    trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /************************** Now set the context engine.  ***************************/
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /****************** *****************  **********************/
    /*                   Now set BOOT COUNT.                    */
    /****************** *****************  **********************/
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /****************** *****************  **********************/
    /*                   Now set BOOT TIME.                    */
    /****************** *****************  **********************/
    agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);

    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Check username length.  */
    if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING))
    {
        return(NX_SIZE_ERROR);
    }

    /****************** *****************  **********************/
    /*                   Now set USER NAME.                     */
    /****************** *****************  **********************/
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Initialize the temporary string to zero. */
    for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
       temp_string[i] =  0;

    /****************** *****************  **********************/
    /*              Now set AUTHENTICATION PARAMETER.           */
    /****************** *****************  **********************/
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)
    {

        /* We have a valid authentication key, so initialize the string to zero. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end);

        trap_authentication_ptr =  trap_buffer_ptr + 2; 

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr);
#endif
    }
    else
    {
        /* No security enabled so set this as an empty parameter. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;


    /****************** *****************  **********************/
    /*              Now set 8 char PRIVACY PARAMETER.           */
    /****************** *****************  **********************/
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {

        /*  We will encrypt the message, so set to all zeros field initially. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end);

        trap_privacy_ptr =  trap_buffer_ptr + 2; 

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr);
#endif
    }
    else
    {
        /* Not encrypting, so set the privacy field as an empty parameter. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* If privacy is required, set the response to have an encryption header.  */ 
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {
              
         /* Now setup the trap buffer to encapsulate the encrypted PDU.  Note that
            the actual encryption will be done after the complete trap has been
            formed.  */
         trap_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
         trap_buffer_ptr[1] =  0x82;
         trap_buffer_ptr[2] =  0x00;
         trap_buffer_ptr[3] =  0x00;

         /* Save the trap encryption size pointer.  This will be filled in below
            as we build the message.  */
         trap_encryption_size_ptr =  trap_buffer_ptr + 2;  

         /* Move the trap buffer forward.  */
         trap_buffer_ptr =  trap_buffer_ptr + 4;

         /* Increase the length of the total trap message.  */
         trap_sequence_length =  trap_sequence_length + 4;
    }

    /* Save the trap pdu sequence pointer.  */
    trap_pdu_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap_pdu_ptr: 0x%x\n", trap_pdu_ptr);
#endif

    /****************** *****************  **********************/
    /*                  Now start the PDU SEQUENCE.             */
    /****************** *****************  **********************/

    /* A zero is written for now.  This will be updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);  

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Increment the number of trap sequence bytes.  */
    trap_sequence_length =       trap_sequence_length + trap_length; 

    /****************************************************/
    /*            Set the PDU engine ID                 */
    /****************************************************/
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (trap_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap pointer forward.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Increment the sequence length.  */
    trap_sequence_length =       trap_sequence_length + trap_length; 

    /* Increment the pdu length.  */
    trap_pdu_length =            trap_pdu_length + trap_length;

    /****************************************************/
    /*            Set the PDU engine name               */
    /****************************************************/
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (trap_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap pointer forward.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Save the pointer to the trap type.  */
    trap_type_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap_type_ptr: 0x%x\n", trap_type_ptr);
#endif

    /* Increment the sequence length.  */
    trap_sequence_length =       trap_sequence_length + trap_length; 
    
    /* Increment the pdu length.  */
    trap_pdu_length =            trap_pdu_length + trap_length;

    /****************************************************/
    /*            Set the PDU request type              */
    /****************************************************/
    trap_length =  _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /****************************************************/
    /*            Set the PDU request ID                */
    /****************************************************/
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up (this assumes two bytes but we may need more) .  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /****************************************************/
    /*            Get the PDU error information         */
    /****************************************************/

    /* Assume everything is okay at this point.  */
    trap_length =  _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the response's variable list field.  */
    trap_variable_list_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap_variable_list_ptr: 0x%x\n", trap_variable_list_ptr);
#endif
    /* Setup the variable list.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); 

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Starting trap_variable_ptr: 0x%x\n", trap_variable_ptr);
#endif

    /****************************************************/
    /*          Start the PDU variable list length      */
    /****************************************************/

    /* Initialize the length to zero.  We will update with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /****************************************************/
    /*             Set the sysUpTime object ID          */
    /****************************************************/

    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", 
                                                  trap_packet_ptr -> nx_packet_data_end); 

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /****************************************************/
    /*             Set the sysUpTime Timer Ticks        */
    /****************************************************/
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_TIME_TICS;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)elapsed_time;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Clear the trap variable size.  */
    trap_variable_length =  0;

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Check for valid trap type. */
    if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM))
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Check that we have a trap list if a custom trap is requested.  */
    if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM))
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Check if this is an enumerated trap type. */
    if (trap_type <= TRAP_ID_MAX)
    {
    
        /* Setup the variable trap sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;
    
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;
    
        /* Place the snmpTrapOID object ID into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", 
                                                      trap_packet_ptr -> nx_packet_data_end); 
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;
    
        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;
    
        /* Set a Object ID for the data.  */
        trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_OBJECT_ID;
        trap_object_data.nx_snmp_object_data_msw =   0;
        _nx_snmp_object_copy(_nx_snmp_v3_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string);

        /* Add trap object data to trap buffer. */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);
    
        /* Check for a valid operation.  */
        if (trap_length == 0)
        {
    
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);
    
            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    
        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;
    
        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;
    
        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;
    
        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;
    
        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;
    
        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

    }

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Default the object pointer to NULL.  */
    trap_object_ptr =  NX_NULL;

    /* Determine if an object is specified.  */
    if (object_list_ptr)
    {

        /* Setup object pointers from the supplied object list.  */
        trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
        trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

        /* Check for a valid operation.  */
        if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
        {
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    }

    /* Loop to process all the objects in the list.  */
    while (trap_object_ptr)
    {

        /* Clear the trap variable length.  */
        trap_variable_length =  0;

        /* Remember the start of the variable.  */
        trap_variable_ptr =  trap_buffer_ptr;

        /* Setup the variable trap sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the object into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Insert the object's data into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Now update the trap variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Default the object pointer to NULL.  */
        trap_object_ptr =  NX_NULL;

        /* Determine if there are more objects to insert into the trap message.  */
        if (object_list_ptr)
        {

            /* Move to the next object in the list.  */
            object_list_ptr++;

            if (object_list_ptr == NX_NULL)
            {
                /* Release the trap packet.  */
                nx_packet_release(trap_packet_ptr);

                /* Done, return to caller.  */
                return(NX_SNMP_ERROR);
            }

            /* Determine if there is another object.  */
            if (object_list_ptr -> nx_snmp_object_string_ptr)
            {

                /* Setup the object and object data pointers.  */
                trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
                trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
                NX_SNMPV3_DBG_PRINTF("Next trap3 object data at 0x%x\n", trap_object_data_ptr);
#endif
                /* Check for a valid operation.  */
                if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
                {
                    /* Release the trap packet.  */
                    nx_packet_release(trap_packet_ptr);

                    /* Done, return to caller.  */
                    return(NX_SNMP_ERROR);
                }
            }
        }
    } 

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("\nSet trap3 sequence length at 0x%x to 0x%x\n  Set global sequence length at 0x%x  to 0x%x\n  Set trap3 security length at 0x%x  to 0x%x\n Set trap3 pdu length at 0x%x  to 0x%x\n Set trap3 variable list length at 0x%x  to 0x%x\n  Set trap3 type length at 0x%x to 0x%x\n",          
                          trap_sequence_ptr, trap_sequence_length, trap_header_ptr, trap_header_length, 
                          trap_security_ptr, trap_security_length, trap_pdu_ptr, trap_pdu_length, 
                          trap_variable_list_ptr, trap_variable_list_length, trap_type_ptr, trap_type_length);
#endif

    /* At this point, several trap fields need to be updated with actual lengths.  */

    _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); 
    _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end);  
    _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end); 
    _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set_1byte(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end); 

    /* Setup the security OCTET string length.  */

    /* Backup to the OCTET string for the security size.  */
    trap_security_ptr =  trap_security_ptr - 2;
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Move trap3 security pointer by 2 0x%x  (length %u)\n",      trap_security_ptr, trap_security_length);
#endif    
    /* Account for the 2 byte Security Sequence field.  */ 
    trap_security_length =  trap_security_length + 2;

    /* Store the security size.  */
    trap_security_ptr[1] =  (UCHAR) (trap_security_length & 0xFF);

    /* Determine if privacy is required.  If so, encrypt the PDU and setup the response
       to have an encryption header.  */ 
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {

        /* Determine if any padding needs to be applied - account for the
           two bytes of sequence information on the PDU.  */
        trap_pdu_length =  trap_pdu_length + 2; 
        padding =  ((trap_pdu_length+7)/8)*8 - trap_pdu_length;

        /* Add the padding the trap PDU length and the trap sequence length.  */
        trap_pdu_length =       trap_pdu_length + padding;
        trap_sequence_length =  trap_sequence_length + padding;

        /* Clear the end of the trap message...  just to be nice!  */
        for (i = 0; i < padding; i++)
        {

            /* Clear byte at the end of the response.  */
            *trap_buffer_ptr++ =  0;
        }
               
        /* Setup the size of the encrypted PDU.  */
        trap_encryption_size_ptr[0] =  (UCHAR) ((trap_pdu_length >> 8) & 0xFF);
        trap_encryption_size_ptr[1] =  (UCHAR) (trap_pdu_length & 0xFF);

        /* Update the total trap sequence length again. */
        _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);

        /* Increment the salt counter.  */
        agent_ptr -> nx_snmp_agent_v3_context_salt_counter++;

        /* Build the salt value for the decryption.  */
        key1[0] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF);
        key1[1] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF);
        key1[2] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >>  8) & 0xFF);
        key1[3] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF);
        key1[4] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF);
        key1[5] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF);
        key1[6] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >>  8) & 0xFF);
        key1[7] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF);

        /* Loop to store the salt in the privacy field.  */
        for (i = 0; i < 8; i++)
        {

            /* Store a byte of the salt.  */
            trap_privacy_ptr[i] =  key1[i];
        }

        /* Setup pointer to the actual PDU.  */
        temp_ptr =  trap_encryption_size_ptr + 2;   

        /* Make the Initialization Vector (IV).  */
        for (i = 0; i < 8; i++)
        {

            key2[i] =  (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i];
        }

        /* Setup the DES.  */
        _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) -> nx_snmp_security_key);

        /* Setup the first input block - use the IV for the first block.  */
        for (i = 0; i < 8; i++)
        {
    
            key1[i] =  temp_ptr[i] ^ key2[i];
        } 

        /* Encrypt the first 8 bytes.  */
        _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]);

        /* Loop to encrypt the rest of the PDU.  */
        j =  8;
        do
        {

            /* Setup the next input block.  */
            for (i = 0; i < 8; i++)
            {

                key1[i] =  temp_ptr[j+i] ^ temp_ptr[(j-8)+i];
            }

            /* Encrypt the next 8 bytes.  */
            _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]);

            /* Move the major index forward.  */
            j =  j + 8;
        } while (j < trap_pdu_length);
    }

    /* Now the trap packet's pointers must be setup so it can be sent.  */
    trap_packet_ptr -> nx_packet_length =  (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr);
    trap_packet_ptr -> nx_packet_append_ptr =  trap_buffer_ptr;

    /* Determine if authentication is required.  */ 
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)
    {

        /* Yes, authentication is required.  */

        /* Now determine which authentication is required.  */
        if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY)
        {

            /* Copy the base MD5 key into key1.  */
            for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base MD5 key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Calculate prepend Key1.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Prepend Key2 to the result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2);
        }
        else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY)
        {

            /* Copy the base SHA key into key1.  */
            for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base SHA key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Calculate prepend Key1.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Prepend Key2 to the result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2);
        }
        else
        {

            /* Increment the authentication error counter.  */
            agent_ptr -> nx_snmp_agent_authentication_errors++;

            /* Release packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* At this point, key2 contains the computed digest of the message.  This needs to be 
           place in the outgoing message.  */

        /* Loop to setup the outgoing digest.  */
        for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
        {

            /* Copy one byte of digest.  */
            trap_authentication_ptr[i] =  key2[i];
        }
    }

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_traps_sent++;
    agent_ptr -> nx_snmp_agent_packets_sent++;
    agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length;

    /* Send the trap packet back to the requesting SNMP manager.  */
    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ip_address, NX_SNMP_MANAGER_TRAP_PORT); 

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return error. */
        return(NX_SNMP_ERROR);
    }

    /* Return successful completion.  */
    return(NX_SUCCESS);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nxe_snmp_agent_trapv3_oid_send                     PORTABLE C      */
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function checks for errors in the SNMP agent v3 trap send      */
/*    function call.                                                      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    agent_ptr                             Pointer to SNMP agent         */
/*    ip_address                            Destination IP address        */
/*    username                              Username                      */
/*    oid                                   Enterprise ID to send         */
/*    elapsed_time                          Elapsed time from last boot   */
/*                                            of the device (sysUpTime)   */
/*    object_list_ptr                       Variable list of application  */
/*                                            objects to present with the */
/*                                            trap                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_snmp_agent_trapv3_send            Actual agent trap send        */
/*                                            function                    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (username == NX_NULL))
        return(NX_PTR_ERROR);

    /* Check for invalid IP address.  */
    if (ip_address == 0)
        return(NX_IP_ADDRESS_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_agent_trapv3_oid_send(agent_ptr, ip_address, username, oid, elapsed_time, object_list_ptr);

    /* Return status.  */
    return(status);
}



/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_snmp_agent_trapv3_oid_send                      PORTABLE C      */
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function builds and sends a SNMP v3 trap message.              */
/*                                                                        */ 
/*    Note: The string length of username and oid are limited by the      */ 
/*    packet payload and NX_SNMP_MAX_OCTET_STRING.                        */ 
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    agent_ptr                             Pointer to SNMP agent         */
/*    ip_address                            Destination IP address        */
/*    username                              Username                      */
/*    OID                                   Enterprise ID to send         */
/*    elapsed_time                          Elapsed time from last boot   */
/*                                            of the device (sysUpTime)   */
/*    object_list_ptr                       Variable list of application  */
/*                                            objects to present with the */
/*                                            trap                        */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_des_key_set                       Setup DES encryption          */
/*    _nx_des_encrypt                       Encrypt bytes                 */
/*    _nx_md5_digest_calculate              MD5 algorithm completion      */
/*    _nx_md5_initialize                    MD5 algorithm initialization  */
/*    _nx_md5_update                        MD5 algorithm computation     */
/*    nx_packet_allocate                    Allocate SNMP trap packet     */
/*    nx_packet_release                     Release SNMP packet           */
/*    nx_udp_socket_send                    Send SNMP trap via UDP        */
/*    _nx_snmp_object_copy                  Copy object                   */
/*    _nx_snmp_utility_error_info_set       Set error information         */
/*    _nx_snmp_utility_octet_set            Set octet string              */
/*    _nx_snmp_utility_object_data_set      Set the data value            */
/*    _nx_snmp_utility_object_id_set        Set the object ID             */
/*    _nx_snmp_utility_sequence_set         Set the ASN.1 sequence        */
/*    _nx_snmp_utility_request_id_set       Set the Request ID            */
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_version_set          Set the SNMP v3               */
/*    _nx_sha1_digest_calculate             SHA algorithm completion      */
/*    _nx_sha1_initialize                   SHA algorithm initialization  */
/*    _nx_sha1_update                       SHA algorithm computation     */
/*    tx_time_get                           Get time                      */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/

UINT  _nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr)
{

UINT                 status;
UINT                 trap_length;
UCHAR                *trap_object_ptr;
NX_SNMP_OBJECT_DATA  trap_object_data;
NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL;
NX_PACKET           *trap_packet_ptr;
UCHAR               *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr;
UINT                 trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length;
UCHAR                temp_string[NX_SNMP_DIGEST_SIZE];
UINT                i;
#ifndef NX_SNMP_NO_SECURITY
UINT                j, padding;
UCHAR               *temp_ptr;
UCHAR               *trap_encryption_size_ptr = NX_NULL;
UCHAR               *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL;
UCHAR               key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR               key2[NX_SNMP_DIGEST_WORKING_SIZE];
#endif
UINT                packet_type = NX_UDP_PACKET;
UCHAR               message_security_options;
UINT                username_length;



    /* Allocate the packet for the SNMP response.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a trap packet was allocated.  */
    if (status != NX_SUCCESS)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return(NX_SNMP_ERROR);

    }


    /* Initialize the counters required for the length fields of the trap packet.  */
    trap_sequence_length =       0;
    trap_header_length =         0;
    trap_security_length =       0;
    trap_pdu_length =            0;
    trap_type_length =           0;
    trap_variable_list_length =  0;
    trap_variable_length =       0;

    /* Setup a pointer to the trap packet's buffer area.  */
    trap_buffer_ptr =  trap_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the trap sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the response.  */
    trap_sequence_ptr =  trap_buffer_ptr;

    /* First, write the sequence in the trap packet.  A zero is written for now.  This will be
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Now set the Version ID in the trap message.  */
    trap_length =  _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Save the pointer to the global header.  */
    trap_header_ptr =  trap_buffer_ptr;

    /* Write the sequence for the global header in the trap packet.  A zero is written for now.
       This will be updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now setup the request ID.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /* Now setup the maximum message size.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /* Now setup the security options.  */
    message_security_options = 0;

    /* Determine what the trap message security options are. These are not the same as
       the general get/set request PDU options.  */
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)
    {
        message_security_options = NX_SNMP_SECURITY_AUTHORIZE;
    }
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {
        message_security_options |= NX_SNMP_SECURITY_PRIVACY;
    }

    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end);


    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /* Now setup the security type.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the header sequence length.  */
    trap_header_length =  trap_header_length + trap_length;

    /* At this point, we have successfully built the security header.  Now, we need to build
       the security parameters field.  */

    /* First setup the octet string field.  */
    trap_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
    trap_buffer_ptr[1] =  0x0;

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + 2;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + 2;

    /* Remember the security header length pointer.  */
    trap_security_ptr =  trap_buffer_ptr;

    /* Now set the sequence of the USM security parameters.  */
    trap_length =  _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Now setup the context engine.  */
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Now setup the number of engine boots.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Now setup the relative time since the last engine boot.  */
    agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Check username length.  */
    if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING))
    {
        return(NX_SIZE_ERROR);
    }

    /* Now setup the user name, as specified by the input parameter.  */
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Now setup the authentication parameter - it is a 12 character field set to zeros initially.  */
    for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
       temp_string[i] =  0;

    /****************** *****************  **********************/
    /*              Now set AUTHENTICATION PARAMETER.           */
    /****************** *****************  **********************/
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)
    {

        /* We have a valid authentication key, so initialize the string to zero. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end);

        trap_authentication_ptr =  trap_buffer_ptr + 2; 

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr);
#endif
    }
    else
    {
        /* No security enabled so set this as an empty parameter. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end);
    }

        /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /****************** *****************  **********************/
    /*              Now set 8 char PRIVACY PARAMETER.           */
    /****************** *****************  **********************/
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {

        /*  We will encrypt the message, so set to all zeros field initially. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end);

        trap_privacy_ptr =  trap_buffer_ptr + 2; 

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr);
#endif
    }
    else
    {
        /* Not encrypting, so set the privacy field as an empty parameter. */
        trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Adjust the security sequence length.  */
    trap_security_length =  trap_security_length + trap_length;

    /* Determine if privacy is required.  If so, decrypt the source PDU and setup the response
       to have an encryption header.  */
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {

#ifndef NX_SNMP_NO_SECURITY

        /* Now setup the trap buffer to encapsulate the encrypted PDU.  Note that
           the actual encryption will be done after the complete trap has been
           formed.  */
        trap_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
        trap_buffer_ptr[1] =  0x82;
        trap_buffer_ptr[2] =  0x00;
        trap_buffer_ptr[3] =  0x00;

        /* Save the trap encryption size pointer.  This will be filled in below
           as we build the message.  */
        trap_encryption_size_ptr =  trap_buffer_ptr + 2;

        /* Move the trap buffer forward.  */
        trap_buffer_ptr =  trap_buffer_ptr + 4;

        /* Increase the length of the total trap message.  */
        trap_sequence_length =  trap_sequence_length + 4;

#else
        /* Encryption is not supported by this agent but is
           specified in the request or by the agent.  Simply
           discard the message.  */

        /* Increment the privacy error counter.  */
        agent_ptr -> nx_snmp_agent_privacy_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
#endif
    }

    /* Save the trap pdu sequence pointer.  */
    trap_pdu_ptr =  trap_buffer_ptr;

    /* First, write the PDU sequence in the trap packet.  A zero is written for now.  This will be
       updated later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Increment the number of trap sequence bytes.  */
    trap_sequence_length =       trap_sequence_length + trap_length;

    /* Now store the PDU context engine in the trap packet.  */
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (trap_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap pointer forward.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Increment the sequence length.  */
    trap_sequence_length =       trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =            trap_pdu_length + trap_length;

    /* Now store the PDU context name in the trap packet.  */
    trap_length =  _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (trap_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap pointer forward.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Save the pointer to the trap type.  */
    trap_type_ptr =  trap_buffer_ptr;

    /* Increment the sequence length.  */
    trap_sequence_length =       trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =            trap_pdu_length + trap_length;

    /* Setup the trap request type field.  */
    trap_length =  _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Now set the request ID in the trap message.  */
    trap_length =  _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Set the trap error information.  Assume everything is okay at this point.  */
    trap_length =  _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the response's variable list field.  */
    trap_variable_list_ptr =  trap_buffer_ptr;

    /* Setup the variable list.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Setup the variable trap sequence.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Place the sysUpTime object ID into the trap buffer.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Insert the object's data into the trap buffer.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_TIME_TICS;
    trap_object_data.nx_snmp_object_data_msw =   (LONG)elapsed_time;
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Remember the start of the variable.  */
    trap_variable_ptr =  trap_buffer_ptr;

    /* Clear the trap variable size.  */
    trap_variable_length =  0;

    /* Setup the variable trap sequence.  For now, the length will be zero.  We
       will overwrite this with the actual length later.  */
    trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Place the snmpTrapOID object ID into the trap buffer.  */
    trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Set a Object ID for the data.  */
    trap_object_data.nx_snmp_object_data_type =  NX_SNMP_ANS1_OBJECT_ID;
    trap_object_data.nx_snmp_object_data_msw =   0;

    /* Check oid length.  */
    if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING))
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string);
    trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (trap_length == 0)
    {

        /* Release the trap packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Done, return to caller.  */
        return(NX_SNMP_ERROR);
    }

    /* Move the trap buffer pointer up.  */
    trap_buffer_ptr =  trap_buffer_ptr + trap_length;

    /* Adjust the trap sequence length.  */
    trap_sequence_length =  trap_sequence_length + trap_length;

    /* Increment the pdu length.  */
    trap_pdu_length =  trap_pdu_length + trap_length;

    /* Adjust the trap request type length.  */
    trap_type_length =  trap_type_length + trap_length;

    /* Adjust the trap variable list size.  */
    trap_variable_list_length =  trap_variable_list_length + trap_length;

    /* Adjust the trap variable size.  */
    trap_variable_length =  trap_variable_length + trap_length;

    /* Now update the trap variable sequence with the actual variable length.  */
    _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

    /* Default the object pointer to NULL.  */
    trap_object_ptr =  NX_NULL;

    /* Determine if an object is specified.  */
    if (object_list_ptr)
    {

        /* Setup object pointers from the supplied object list.  */
        trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
        trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

        /* Check for a valid operation.  */
        if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
        {
            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }
    }

    /* Loop to process all the objects in the list.  */
    while (trap_object_ptr)
    {

        /* Clear the trap variable length.  */
        trap_variable_length =  0;

        /* Remember the start of the variable.  */
        trap_variable_ptr =  trap_buffer_ptr;

        /* Setup the variable trap sequence.  For now, the length will be zero.  We
           will overwrite this with the actual length later.  */
        trap_length =  _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Place the object into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Insert the object's data into the trap buffer.  */
        trap_length =  _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (trap_length == 0)
        {

            /* Release the trap packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Done, return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* Move the trap buffer pointer up.  */
        trap_buffer_ptr =  trap_buffer_ptr + trap_length;

        /* Adjust the trap sequence length.  */
        trap_sequence_length =  trap_sequence_length + trap_length;

        /* Increment the pdu length.  */
        trap_pdu_length =  trap_pdu_length + trap_length;

        /* Adjust the trap request type length.  */
        trap_type_length =  trap_type_length + trap_length;

        /* Adjust the trap variable list size.  */
        trap_variable_list_length =  trap_variable_list_length + trap_length;

        /* Adjust the trap variable size.  */
        trap_variable_length =  trap_variable_length + trap_length;

        /* Now update the trap variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end);

        /* Default the object pointer to NULL.  */
        trap_object_ptr =  NX_NULL;

        /* Determine if there are more objects to insert into the trap message.  */
        if (object_list_ptr)
        {

            /* Move to the next object in the list.  */
            object_list_ptr++;

            if (object_list_ptr == NX_NULL)
            {
                /* Release the trap packet.  */
                nx_packet_release(trap_packet_ptr);

                /* Done, return to caller.  */
                return(NX_SNMP_ERROR);
            }

            /* Determine if there is another object.  */
            if (object_list_ptr -> nx_snmp_object_string_ptr)
            {

                /* Setup the object and object data pointers.  */
                trap_object_ptr =       object_list_ptr -> nx_snmp_object_string_ptr;
                trap_object_data_ptr =  object_list_ptr -> nx_snmp_object_data;

                /* Check for a valid operation.  */
                if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL)
                {
                    /* Release the trap packet.  */
                    nx_packet_release(trap_packet_ptr);

                    /* Done, return to caller.  */
                    return(NX_SNMP_ERROR);
                }
            }
        }
    }

    /* At this point, several trap fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end);

    /* Setup the security OCTET string length.  */

    /* Backup to the OCTET string for the security size.  */
    trap_security_ptr =  trap_security_ptr - 2;

    /* Account for the 2 byte Security Sequence field.  */
    trap_security_length =  trap_security_length + 2;

    /* Store the security size.  */
    trap_security_ptr[1] =  (UCHAR) (trap_security_length & 0xFF);

    /* Determine if privacy is required.  If so, encrypt the PDU and setup the response
       to have an encryption header.  */
    if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)
    {

#ifndef NX_SNMP_NO_SECURITY

        /* Determine if any padding needs to be applied - account for the
           four bytes of header information on the PDU.  */
        trap_pdu_length =  trap_pdu_length + 4;
        padding =  ((trap_pdu_length+7)/8)*8 - trap_pdu_length;

        /* Add the padding the trap PDU length and the trap sequence length.  */
        trap_pdu_length =       trap_pdu_length + padding;
        trap_sequence_length =  trap_sequence_length + padding;

        /* Clear the end of the trap message...  just to be nice!  */
        for (i = 0; i < padding; i++)
        {

            /* Clear byte at the end of the response.  */
            *trap_buffer_ptr++ =  0;
        }

        /* Setup the size of the encrypted PDU.  */
        trap_encryption_size_ptr[0] =  (UCHAR) ((trap_pdu_length >> 8) & 0xFF);
        trap_encryption_size_ptr[1] =  (UCHAR) (trap_pdu_length & 0xFF);

        /* Update the total trap sequence length again. */
        _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end);

        /* Increment the salt counter.  */
        agent_ptr -> nx_snmp_agent_v3_context_salt_counter++;

        /* Build the salt value for the decryption.  */
        key1[0] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF);
        key1[1] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF);
        key1[2] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >>  8) & 0xFF);
        key1[3] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF);
        key1[4] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF);
        key1[5] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF);
        key1[6] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >>  8) & 0xFF);
        key1[7] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF);

        /* Loop to store the salt in the privacy field.  */
        for (i = 0; i < 8; i++)
        {

            /* Store a byte of the salt.  */
            trap_privacy_ptr[i] =  key1[i];
        }

        /* Setup pointer to the actual PDU.  */
        temp_ptr =  trap_encryption_size_ptr + 2;

        /* Make the Initialization Vector (IV).  */
        for (i = 0; i < 8; i++)
        {

            key2[i] =  (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i];
        }

        /* Setup the DES.  */
        _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key);

        /* Setup the first input block - use the IV for the first block.  */
        for (i = 0; i < 8; i++)
        {

            key1[i] =  temp_ptr[i] ^ key2[i];
        }

        /* Encrypt the first 8 bytes.  */
        _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]);

        /* Loop to encrypt the rest of the PDU.  */
        j =  8;
        do
        {

            /* Setup the next input block.  */
            for (i = 0; i < 8; i++)
            {

                key1[i] =  temp_ptr[j+i] ^ temp_ptr[(j-8)+i];
            }

            /* Encrypt the next 8 bytes.  */
            _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]);

            /* Move the major index forward.  */
            j =  j + 8;
        } while (j < trap_pdu_length);

#else

        /* Increment the privacy error counter.  */
        agent_ptr -> nx_snmp_agent_privacy_errors++;

        /* Release the trap packet too.  */
        nx_packet_release(trap_packet_ptr);

        /* Return to caller.  */
        return NX_SNMP_ERROR;
#endif
    }

    /* Now the trap packet's pointers must be setup so it can be sent.  */
    trap_packet_ptr -> nx_packet_length =  (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr);
    trap_packet_ptr -> nx_packet_append_ptr =  trap_buffer_ptr;

#ifndef NX_SNMP_NO_SECURITY

    /* Determine if authentication is required.  */
    if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key)     
    {

        /* Yes, authentication is required.  */

        /* Now determine which authentication is required.  */
        if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY)
        {

            /* Copy the base MD5 key into key1.  */
            for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base MD5 key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i];
            }

            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Calculate prepend Key1.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the message.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Prepend Key2 to the result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2);
        }
        else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY)
        {

            /* Copy the base SHA key into key1.  */
            for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base SHA key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i];
            }

            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Calculate prepend Key1.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the message.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Prepend Key2 to the result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2);
        }
        else
        {

            /* Increment the authentication error counter.  */
            agent_ptr -> nx_snmp_agent_authentication_errors++;

            /* Release packet.  */
            nx_packet_release(trap_packet_ptr);

            /* Return to caller.  */
            return(NX_SNMP_ERROR);
        }

        /* At this point, key2 contains the computed digest of the message.  This needs to be
           place in the outgoing message.  */

        /* Loop to setup the outgoing digest.  */
        for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
        {

            /* Copy one byte of digest.  */
            trap_authentication_ptr[i] =  key2[i];
        }
    }
#endif

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_traps_sent++;
    agent_ptr -> nx_snmp_agent_packets_sent++;
    agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length;

    /* Send the trap packet back to the requesting SNMP manager.  */

    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ip_address, NX_SNMP_MANAGER_TRAP_PORT);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(trap_packet_ptr);

        /* Return error. */
        return(NX_SNMP_ERROR);
    }

    /* Return successful completion.  */
    return(NX_SUCCESS);
}


#endif /* NX_SNMP_DISABLE_V3 */


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_compare                            PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object compare    */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    requested_object                      Pointer to requested object   */ 
/*    actual_object                         Pointer to actual object      */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_compare               Actual agent object compare   */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((requested_object == NX_NULL) || (actual_object == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_compare(requested_object, actual_object);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_compare                             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function compares two objects.                                 */ 
/*                                                                        */ 
/*    Note: new API nx_snmp_object_compare_extended is encouraged to use. */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    requested_object                      Pointer to requested object   */ 
/*    actual_object                         Pointer to actual object      */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_compare_extended      Call actual compare service   */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object)
{

UINT    status;
UINT    requested_object_length;
UINT    actual_object_length;


    /* Calculate the object length.  */
    if ((_nx_utility_string_length_check((CHAR *)requested_object, &requested_object_length, NX_MAX_STRING_LENGTH)) ||
        (_nx_utility_string_length_check((CHAR *)actual_object, &actual_object_length, NX_MAX_STRING_LENGTH)))
    {
        return(NX_SIZE_ERROR);
    }

    /* Call actual service.  */
    status = _nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length);

    /* Return status to the caller.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_compare_extended                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object compare    */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    requested_object                      Pointer to requested object   */ 
/*    requested_object_length               Length of object requested    */ 
/*    actual_object                         Pointer to actual object      */ 
/*    actual_object_length                  Length of object requested    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_compare_extended      Actual agent object compare   */ 
/*                                            extended function           */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length)
{


    /* Check for invalid input pointers.  */
    if ((requested_object == NX_NULL) || (actual_object == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    return(_nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length));
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_compare_extended                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function compares two objects.                                 */ 
/*                                                                        */ 
/*    Note: The strings of requested object and actual object must be     */
/*    NULL-terminated and length of each string matches the length        */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    requested_object                      Pointer to requested object   */ 
/*    requested_object_length               Length of object requested    */ 
/*    actual_object                         Pointer to actual object      */ 
/*    actual_object_length                  Length of object requested    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length)
{

UINT    i, j;
UINT    request_value;
UINT    actual_value;
UINT    temp_requested_object_length;
UINT    temp_actual_object_lenght;


    /* Check object string and get the actual string length.  */
    if ((_nx_utility_string_length_check((CHAR *)requested_object, &temp_requested_object_length, requested_object_length)) ||
        (_nx_utility_string_length_check((CHAR *)actual_object, &temp_actual_object_lenght, actual_object_length)))
        return(NX_SNMP_ERROR);

    /* Check the actual string length.  */
    if ((requested_object_length != temp_requested_object_length) ||
        (actual_object_length != temp_actual_object_lenght))
        return(NX_SNMP_ERROR);

    /* Loop to compare the first and second object name.  Stop at the first NULL.  */
    i =  0;
    request_value =  0;
    actual_value =   0;
    while ((requested_object[i]) && (actual_object[i]))
    {

        /* Update the requested object value.  */
        if (requested_object[i] == '.')
            request_value =  0;
        else
            request_value =  (request_value * 10) + (UINT) (requested_object[i] - '0');

        /* Update the actual object value.  */
        if (actual_object[i] == '.')
            actual_value =  0;
        else
            actual_value =  (actual_value * 10) + (UINT) (actual_object[i] - '0');

        /* Determine if the names are different.  */
        if (requested_object[i] != actual_object[i])
        {

            /* Calculate the remainder - if any - of the requested value.  */
            j =  i;
            while ((requested_object[j]) && (requested_object[j] != '.'))
            {

                /* Update the request value.  */
                request_value =  (request_value * 10) + (UINT) (requested_object[j] - '0');

                /* Move to next entry.  */
                j++;
            }


            /* Calculate the remainder - if any - of the actual value.  */
            j =  i;
            while ((actual_object[j]) && (actual_object[j] != '.'))
            {

                /* Update the actual value.  */
                actual_value =  (actual_value * 10) + (UINT) (actual_object[j] - '0');

                /* Move to next entry.  */
                j++;
            }

            /* Determine if the requested object name is less than the actual object name.  */
            if (request_value < actual_value)
                return(NX_SNMP_NEXT_ENTRY);
            else
                break;
        }

        /* Move to next character.  */
        i++;
    }

    /* Now compare the names to check for a successful match.  */
    if ((requested_object[i] == NX_NULL) && (actual_object[i] == NX_NULL))
        return(NX_SUCCESS);

    /* If the actual object is NULL, that means that everything else matched exactly.  */
    if (actual_object[i] == NX_NULL)
        return(NX_SUCCESS);

    /* Determine if the requested object name is NULL.  This case is considered the next entry.  */
    if (requested_object[i] == NX_NULL)
        return(NX_SNMP_NEXT_ENTRY);

    /* Return an error condition.  */
    return(NX_SNMP_ERROR);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_copy                               PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object copy       */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_object_name                    Pointer to source object      */ 
/*    destination_object_name               Pointer to destination object */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    size                                  If error, returns zero, else  */
/*                                            returns number of bytes     */
/*                                            copied                      */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_copy                  Actual agent object copy      */ 
/*                                            function                    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_object_name == NX_NULL) || (destination_object_name == NX_NULL))
        return(0);

    /* Call actual service.  */
    status =  _nx_snmp_object_copy(source_object_name, destination_object_name);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_copy                                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function copies the source object to the destination object.   */ 
/*                                                                        */ 
/*    Note: new API nx_snmp_object_copy_extended is encouraged to use. */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_object_name                    Pointer to source object      */ 
/*    destination_object_name               Pointer to destination object */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    size                                  If error, returns zero, else  */
/*                                            returns number of bytes     */
/*                                            copied                      */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name)
{

UINT    i;


    /* Calculate the object length.  */
    if (_nx_utility_string_length_check((CHAR *)source_object_name, NX_NULL, NX_MAX_STRING_LENGTH))
        return(0);

    /* Loop to copy the name.  */
    i =  0;

    while (source_object_name[i])
    {

        /* Copy a byte of the name.  */
        destination_object_name[i] =  source_object_name[i];

        /* Move to next byte.  */
        i++;
    }

    /* Ensure name is null terminated.  */
    destination_object_name[i] =  NX_NULL;

    /* Return the size of the name.  */
    return(i); 
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_copy_extended                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object copy       */ 
/*    function call.                                                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_object_name                    Pointer to source object      */ 
/*    source_object_name_length             Length of source object       */ 
/*    destination_object_name_buffer        Pointer to destination object */ 
/*    destination_object_name_buffer_size   Size of destination object    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    size                                  If error, returns zero, else  */
/*                                            returns number of bytes     */
/*                                            copied                      */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_copy_extended         Actual agent object copy      */ 
/*                                            extended function           */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length,
                                     UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size)
{


    /* Check for invalid input pointers.  */
    if ((source_object_name == NX_NULL) || (destination_object_name_buffer == NX_NULL))
        return(0);

    /* Call actual service.  */
    return(_nx_snmp_object_copy_extended(source_object_name, source_object_name_length, destination_object_name_buffer, destination_object_name_buffer_size));
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_copy_extended                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function copies the source object to the destination object.   */ 
/*                                                                        */ 
/*    Note: the object name must be NULL-terminated, the size of          */ 
/*    destination object buffer must be larger than source object length. */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_object_name                    Pointer to source object      */ 
/*    source_object_name_length             Length of source object       */ 
/*    destination_object_name_buffer        Pointer to destination object */ 
/*    destination_object_name_buffer_size   Size of destination object    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    size                                  If error, returns zero, else  */
/*                                            returns number of bytes     */
/*                                            copied                      */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length,
                                    UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size)
{

UINT    temp_object_name_length;


    /* Check the string length, the destination oject name buffer size must be larger than source object name length.  */
    if ((source_object_name_length == 0) || (destination_object_name_buffer_size <= source_object_name_length))
        return(0);

    /* Check name string.  */
    if (_nx_utility_string_length_check((CHAR *)source_object_name, &temp_object_name_length, source_object_name_length))
        return(0);

    /* Check the actual string length.  */
    if (source_object_name_length != temp_object_name_length)
        return(0);

    /* Copy the name and null-terminator.  */
    memcpy(destination_object_name_buffer, source_object_name, source_object_name_length + 1);

    /* Return the size of the name.  */
    return(source_object_name_length); 
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_counter_get                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object counter    */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to counter source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter_get           Actual agent object counter   */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_counter_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter_get                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object counter from the specified       */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to counter source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_COUNTER;

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG)(*value_ptr);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_counter_set                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object counter    */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to counter destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter_set           Actual agent object counter   */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_counter_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter_set                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object counter from the object data     */
/*    structure and places it in the destination.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to counter destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) destination_ptr;

    /* Copy the value into the object data structure.  */
    *value_ptr =  (ULONG)(object_data -> nx_snmp_object_data_msw);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_counter64_get                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent 64-bit object     */ 
/*    counter get function call.                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to counter source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter64_get         Actual agent object counter   */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_counter64_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter64_get                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the 64-bit object counter from the          */
/*    specified source location.                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to counter source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_COUNTER64;

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG)value_ptr[0];
    object_data -> nx_snmp_object_data_lsw =  (LONG)value_ptr[1];

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_counter64_set                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent 64-bit object     */ 
/*    counter set function call.                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to counter destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter64_set         Actual agent object counter   */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_counter64_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_counter64_set                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the 64-bit object counter from the object   */
/*    data structure and places it in the destination.                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to counter destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG       *value_ptr;
LONG         temp = 0;

    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER64)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) destination_ptr;

    if (object_data -> nx_snmp_object_data_lsw  == 0)
    {
        temp = object_data -> nx_snmp_object_data_msw;
        value_ptr[0] = 0;

    }
    if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFFFF00) == 0)
    {
        temp = object_data -> nx_snmp_object_data_msw << 8;
        value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 24) & (0x000000FF));
    }
    else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFF0000) == 0)
    {

        temp = object_data -> nx_snmp_object_data_msw << 16;
        value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 16) & (0x0000FFFF));
    }
    else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFF000000) == 0)
    {

        temp = object_data -> nx_snmp_object_data_msw << 24;
        value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 8) & (0x00FFFFFF));
    }
    else
    {
        value_ptr[0] = (ULONG)(object_data -> nx_snmp_object_data_msw);
    }

    value_ptr[1] = (ULONG)(object_data -> nx_snmp_object_data_lsw + temp);

    /* Value_ptr udpates the MIB data but we also need to display the data correctly in object. */

    /* Update the object data to make the display correct as well. */
    object_data -> nx_snmp_object_data_lsw = (LONG)value_ptr[1];
    object_data -> nx_snmp_object_data_msw = (LONG)value_ptr[0];

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_end_of_mib                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent end-of-mib object */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used                      */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_end_of_mib            Actual agent object end-of-mib*/ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointer.  */
    if (object_data == NX_NULL)
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_end_of_mib(not_used_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_end_of_mib                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places an end-of-mib value in the object data         */ 
/*    structure.                                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used                      */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =  NX_SNMP_ANS1_END_OF_MIB_VIEW;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG) not_used_ptr;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_gauge_get                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object gauge      */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to gauge source       */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_gauge_get             Actual agent object gauge     */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_gauge_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_gauge_get                           PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object gauge from the specified         */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to gauge source       */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_GAUGE;

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG)(*value_ptr);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_gauge_set                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object gauge      */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to gauge destination  */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_gauge_set             Actual agent object gauge     */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_gauge_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_gauge_set                           PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object gauge from the object data       */
/*    structure and places it in the destination.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to gauge destination  */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_GAUGE)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) destination_ptr;

    /* Copy the value into the object data structure.  */
    *value_ptr =  (ULONG)(object_data -> nx_snmp_object_data_msw);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_id_get                             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object ID         */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to ID source          */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_id_get                Actual agent object ID        */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_id_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_id_get                              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object ID from the specified            */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to object ID source   */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    length;
UCHAR   c;
CHAR   *copy_source = (CHAR*)source_ptr;           

     c = *((UCHAR *)source_ptr);

     /* Check if this is an empty string. */
     if ((c == 0x0) || (c == '0'))
     {
         copy_source = "0.0.0";
     }

     /* Check string length.  */
     if (_nx_utility_string_length_check((CHAR *)copy_source, &length, NX_SNMP_MAX_OCTET_STRING))
     {
         /* Incoming object data is too big to fit in. */
         return(NX_SNMP_ERROR);
     }

     object_data -> nx_snmp_object_data_type = NX_SNMP_OBJECT_ID;

     memcpy(&object_data -> nx_snmp_object_octet_string[0], copy_source, length);

     /* NULL-terminate the string. */
     object_data -> nx_snmp_object_octet_string[length] = 0x0;

     /* Calculate the length.  */
     object_data -> nx_snmp_object_octet_string_size =  length;

     /* Return success.  */
     return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_id_set                             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object ID         */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to ID destination     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_id_set                Actual agent object ID        */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_id_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_id_set                              PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object ID from the object data          */
/*    structure and places it in the destination.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to ID destination     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_OBJECT_ID)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Copy the object id into the destination string.  */
    _nx_snmp_object_copy(object_data -> nx_snmp_object_octet_string, (UCHAR *) destination_ptr);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_integer_get                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object integer    */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to integer source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_integer_get           Actual agent integer          */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_integer_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_integer_get                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object integer from the specified       */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to integer source     */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

LONG   *value_ptr;


    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_INTEGER;

    /* Setup pointer to the value.  */
    value_ptr =  (LONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  *value_ptr;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_integer_set                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object integer    */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to integer destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_integer_set           Actual agent object integer   */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_integer_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_integer_set                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object integer from the object data     */
/*    structure and places it in the destination.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to integer destination*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

LONG   *value_ptr;


    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_INTEGER)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (LONG *) destination_ptr;

    /* Copy the value into the object data structure.  */
    *value_ptr =  object_data -> nx_snmp_object_data_msw;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_ip_address_get                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object IP address */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to IP address source  */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_ip_address_get        Actual agent IP address       */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_ip_address_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_ip_address_get                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object IP address from the specified    */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to IP address source  */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{


ULONG   *value_ptr;

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_ANS1_IP_ADDRESS;

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG)(*value_ptr);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_ip_address_set                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object IP address */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to IP address         */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_ip_address_set        Actual agent object IP address*/ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_ip_address_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_ip_address_set                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object IP address from the object data  */
/*    structure and places it in the destination.                         */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to IP address         */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{


ULONG   *value_ptr;

    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_IP_ADDRESS)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) destination_ptr;

    /* Copy the value into the object data structure.  */
    *value_ptr =  (ULONG)(object_data -> nx_snmp_object_data_msw);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_no_instance                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object no-instance*/ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used pointer              */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_no_instance           Actual agent object           */ 
/*                                            no-instance set function    */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if (object_data == NX_NULL)
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_no_instance(not_used_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_no_instance                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places a no-instance value in the object data         */ 
/*    structure.                                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used                      */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =  NX_SNMP_ANS1_NO_SUCH_INSTANCE;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG) not_used_ptr;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_not_found                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent object not-found  */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used pointer              */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_not_found             Actual agent object           */ 
/*                                            not-found set function      */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if (object_data == NX_NULL)
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_not_found(not_used_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_not_found                           PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places an not-found value in the object data          */ 
/*    structure.                                                          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    not_used_ptr                          Not used                      */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =  NX_SNMP_ANS1_NO_SUCH_OBJECT;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG) not_used_ptr;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_octet_string_get                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent octet string      */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to octet string source*/ 
/*    object_data                           Pointer to object data struct */ 
/*    length                                Length of octet string        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_octet_string_get      Actual agent octet string     */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length) 
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_octet_string_get(source_ptr, object_data, length) ;

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_octet_string_get                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object octet string from the specified  */
/*    source location. Note that while this does have a length field      */ 
/*    the caller must set the nx_snmp_object_string_size before calling   */
/*    this function since it supplies the length.                         */
/*                                                                        */ 
/*    The length field is deprecated. It is only included for legacy code.*/
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to octet string source*/ 
/*    object_data                           Pointer to object data struct */ 
/*    length                                Length of octet string        */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length)  
{

UINT    i;
UCHAR   *source_string;


    NX_PARAMETER_NOT_USED(length);

    /* Setup pointer to source string.  */
    source_string =  (UCHAR *) source_ptr;

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_OCTET_STRING;

    if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) 
    {
        return NX_SNMP_ERROR_TOOBIG;
    }

    /* Copy this string into the destination.  */
    for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++)
    {

        /* Copy character.  */
        object_data -> nx_snmp_object_octet_string[i] =  source_string[i];
    }

    /* The length input is deprecated. The caller sets the length from the MIB table 
       entry to the object_data instance before calling this function. */

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_octet_string_set                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent octet string      */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to octet string       */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_octet_string_set      Actual agent octet string     */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_octet_string_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_octet_string_set                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object octet string from the object     */
/*    data structure and places it in the destination.  Note that the     */
/*    length of the octet string must be set in the object string size.   */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to octet string       */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    i;
UCHAR   *string_ptr;


    /* Check for the proper type.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) 
    {
        return NX_SNMP_ERROR_TOOBIG;
    }

    /* Setup pointer to the destination string.  */
    string_ptr =  (UCHAR *) destination_ptr;

    /* Copy this string into the destination.  */
    for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++)
    {

        /* Determine if the string is too big.  */
        if (i >= NX_SNMP_MAX_OCTET_STRING)
        {

            /* Error, source string is too large.  */
            string_ptr[0] =  NX_NULL;
            return(NX_SNMP_ERROR);
        }

        /* Copy character.  */
        string_ptr[i] =  object_data -> nx_snmp_object_octet_string[i];
    }

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_string_get                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent string            */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to string source      */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_string_get            Actual agent string           */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_string_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_string_get                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object ASCII string from the specified  */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to ASCII string source*/ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    i;
UCHAR   *source_string;


    /* Setup pointer to source string.  */
    source_string =  (UCHAR *) source_ptr;

    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_OCTET_STRING;

    /* Copy this string into the destination.  */
    i =  0;
    while (source_string[i])
    {

        /* Copy character.  */
        object_data -> nx_snmp_object_octet_string[i] =  source_string[i];

        /* Move to next character.  */
        i++;
                
        /* Check for size of source string.  */
        if (i >= NX_SNMP_MAX_OCTET_STRING)
        {

            /* Error, source string is too large.  */
            object_data -> nx_snmp_object_octet_string[0] =     NX_NULL;
            object_data -> nx_snmp_object_octet_string_size =   0;
            return(NX_SNMP_ERROR);
        }
    }

    /* Store the length of the string in the object data area.  */
    object_data -> nx_snmp_object_octet_string_size =   i;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_string_set                         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent string            */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to string             */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_string_set             Actual agent string          */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_string_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_string_set                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object ASCII string from the object     */
/*    data structure and places it in the destination.                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to ASCII string       */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    i;
UCHAR   *string_ptr;


    /* Check for the proper type.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the destination string.  */
    string_ptr =  (UCHAR *) destination_ptr;

    /* Copy this string into the destination.  */    
    for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++)
    {

        /* Determine if the string is too big.  */
        if (i >= NX_SNMP_MAX_OCTET_STRING)
        {

            /* Error, source string is too large.  */
            return(NX_SNMP_ERROR);
        }

        /* Copy character.  */
        string_ptr[i] =  object_data -> nx_snmp_object_octet_string[i];
    }

    /* Null terminate the destination.  */
    string_ptr[i] =  NX_NULL;

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_timetics_get                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent timetics          */ 
/*    get function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to timetics source    */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_timetics_get          Actual agent timetics         */ 
/*                                            get function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((source_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_timetics_get(source_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_timetics_get                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object timetics from the specified      */
/*    source location.                                                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    source_ptr                            Pointer to timetics source    */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Setup the object data structure.  */
    object_data -> nx_snmp_object_data_type =   NX_SNMP_TIME_TICS;

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) source_ptr;

    /* Copy the value into the object data structure.  */
    object_data -> nx_snmp_object_data_msw =  (LONG)(*value_ptr);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nxe_snmp_object_timetics_set                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function checks for errors in the SNMP agent timetics          */ 
/*    set function call.                                                  */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to timetics           */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_object_timetics_set          Actual agent timetics         */ 
/*                                            set function                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nxe_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

UINT    status;


    /* Check for invalid input pointers.  */
    if ((destination_ptr == NX_NULL) || (object_data == NX_NULL))
        return(NX_PTR_ERROR);

    /* Call actual service.  */
    status =  _nx_snmp_object_timetics_set(destination_ptr, object_data);

    /* Return status.  */
    return(status);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_object_timetics_set                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object timetics from the object         */
/*    data structure and places it in the destination.                    */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    destination_ptr                       Pointer to timetics           */ 
/*                                            destination                 */ 
/*    object_data                           Pointer to object data struct */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    status                                Completion status             */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    Application Code                                                    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data)
{

ULONG   *value_ptr;


    /* Determine if the correct type is specified.  */
    if (object_data -> nx_snmp_object_data_type != NX_SNMP_TIME_TICS)
    {

        /* Return an invalid type message.  */
        return(NX_SNMP_ERROR_WRONGTYPE);
    }

    /* Setup pointer to the value.  */
    value_ptr =  (ULONG *) destination_ptr;

    /* Copy the value into the object data structure.  */
    *value_ptr =  (ULONG)(object_data -> nx_snmp_object_data_msw);

    /* Return success.  */
    return(NX_SUCCESS);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_community_get                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the community string from the supplied      */
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    community_string                      Pointer to place community    */ 
/*                                            string                      */ 
/*    buffer_length                         Size of input buffer          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            SNMP v1 request processing    */ 
/*    _nx_snmp_version_2_process            SNMP v2 request processing    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_community_get(UCHAR *buffer_ptr, UCHAR *community_string, INT buffer_length)
{

UINT    i;
UINT    length;
UINT    total;


    /* Buffer size must be at least 2 bytes. */
    if (buffer_length < 2)
    {
        return(0);
    }

    /* Set community string to NULL.  */
    *community_string =  NX_NULL;

    /* First see if the ANS1 string type is present.  */
    if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING)
    {

        /* Return a zero length.  */
        return(0);
    }

    if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES)
    {

    /* Get the type of length of the string */
    UINT temp = (UINT)(buffer_ptr[1] & 0x7F);

        if (temp == 2)
        {

            /* Check the buffer length.  */
            if (buffer_length < 4)
            {
                return(0);
            }

            /* Length is in the next two bytes. Example: 0x04 0x82 0x98 0x01 */
            total =  (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]);
    
            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 4;
    
            /* Initialize the length.  */
            length =  4;
        }
    
        else if (temp == 1)
        {

            /* Check the buffer length.  */
            if (buffer_length < 3)
            {
                return(0);
            }

            /* Length is in the next byte. Example: 0x04 0x81 0x98 */
            total =  (UINT)(buffer_ptr[2]) ;
    
            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 3;
    
            /* Initialize the length.  */
            length =  3;
        }
        else
        {
        
            /* String is either null or too big, return a zero length to indicate an error.  */
            return(0);
        }
    }
    else
    {

        /* Otherwise, assume we have one byte. Example: 0x04 0x98 */

        /*  Pickup the total length of the community character string.  */
        total =  (UINT) buffer_ptr[1];

        /* Move the buffer pointer forward.  */
        buffer_ptr =  buffer_ptr + 2;

        /* Initialize the length.  */
        length =  2;
    }

    if ((INT)(length + total) > buffer_length)
    {

        /* Buffer is too small. */
        return(0);
    }

    /* Determine if the length is within the maximum.  */
    if (total > (NX_SNMP_MAX_USER_NAME-1))
    {

        /* String is too big, return a zero length to indicate an error.  */
        return(0);
    }

    /* Loop to pickup the remaining characters in the community string.  */
    for (i = 0; i < total; i++)
    {

        /* Move character from buffer into community string.  */
        *community_string++ =  *buffer_ptr++;

        /* Adjust the length.  */
        length++;
    }

    /* NULL-terminate the community string.  */
    *community_string =  NX_NULL;

    /* Return the length of the ANS1 string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_community_set                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the community string into the supplied         */
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    community_string                      Pointer to source of the      */ 
/*                                            community string            */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Send SNMP v1 trap             */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_community_set(UCHAR *buffer_ptr, UCHAR *community_string, UCHAR *buffer_end)
{

UINT    i;
UINT    header_size;
UINT    length;


    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* First, set the OCTET byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_OCTET_STRING;  

    /* Calculate the length byte.  */
    if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME))
    {

        /* Error, community length is too large.  */
        return(0);
    }

    /* Check for a length greater than 128.  */
    if (length >= 128)
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < (3 + length))
            return(0);

        /* Indicate there are two length bytes.  */
        *buffer_ptr++ =  (UCHAR) 0x82;

        /* Set the first length byte.  */
        *buffer_ptr++ =  (UCHAR) (length >> 8);

        /* Set the second length byte.  */
        *buffer_ptr++ =  (UCHAR) (length & 0xFF);

        /* Set the header size.  */
        header_size =  4;
    }
    else
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < (1 + length))
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) length;

        /* The header is 2 bytes.  */
        header_size =  2;
    }

    /* Loop to store rest of the community string.  */
    for (i = 0; i < length; i++)
    {

        /* Store the SNMP community string.  */
        *buffer_ptr++ =  (UCHAR) community_string[i];
    }

    /* Return the length of the community string.  */
    return(length+header_size);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_error_info_get                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the error information from the supplied     */
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    error_code                            Pointer to place error code   */ 
/*    error_index                           Pointer to place error index  */ 
/*    buffer_length                         Size of input buffer          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_error_info_get(UCHAR *buffer_ptr, UINT *error_code, UINT *error_index, INT buffer_length)
{

    /* Check for invalid input. */
    if (buffer_length < 6)
    {
        /* Invalid input. */
        *error_code =   0;
        *error_index =  0;

        /* Return a zero length.  */
        return(0);
    }

    /* Determine if the error code and error index is correct.  */
    if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) &&
        (buffer_ptr[1] == 1) && 
        (buffer_ptr[3] == NX_SNMP_ANS1_INTEGER) &&
        (buffer_ptr[4] == 1))
    {

        /* Yes, the SNMP version string is correct.  */

        /* Return the error code and error index.  */
        *error_code =  (UINT) buffer_ptr[2];
        *error_index = (UINT) buffer_ptr[5];

        /* Return the length of the error code/index string.  */
        return(6);
    }
    else
    {

        /* No, the SNMP error code/index is invalid.  */

        /* Clear both.  */
        *error_code =   0;
        *error_index =  0;

        /* Return a zero length.  */
        return(0);
    }
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_error_info_set                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the error information into the supplied        */
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    error_code                            Error code                    */
/*    error_index                           Error index                   */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_error_response       Send error response to Manager*/ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_error_info_set(UCHAR *buffer_ptr, UINT error_code, UINT error_index, UCHAR *buffer_end)
{

    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 6)
        return(0);

    /* First, set the INTEGER byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_INTEGER;  

    /* Next set the length byte.  */
    *buffer_ptr++ =  (UCHAR) 1;

    /* Store the error code.  */
    *buffer_ptr++ =  (UCHAR) (error_code & 0xFF);

    /* Set the INTEGER byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_INTEGER;  

    /* Next set the length byte.  */
    *buffer_ptr++ =  (UCHAR) 1;

    /* Store the error index.  */
    *buffer_ptr++ =  (UCHAR) (error_index & 0xFF);

    /* Return the length of the error info.  */
    return(6);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_id_get                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object ID from the supplied buffer      */
/*    and converts the object ID to an ASCII format.                      */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    object_string                         Pointer to place object string*/ 
/*    buffer_length                         Size of input buffer          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_data_get      Get object data               */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_object_id_get(UCHAR *buffer_ptr, UCHAR *object_string, INT buffer_length)
{

UINT    i;
UINT    length;
ULONG   value;
ULONG   temp;
ULONG   multiply;
UINT    total;
UINT    size;
UCHAR   byte;
UCHAR   saved_byte;
UCHAR  *saved_ptr;
UINT    string_length;
    

    /* Buffer size must be at least 4 bytes. */
    if (buffer_length < 4)
    {
        return 0;
    }

    /* Set object string to NULL.  */
    *object_string =  NX_NULL;

    /* Initialize the string length to 0.  */
    string_length = 0;

    /* Initialize the sequence byte value to NULL. */
    value = 0; 

    /* First see if the ANS1 object type is present.  */
    if (buffer_ptr[0] != NX_SNMP_ANS1_OBJECT_ID)
    {

        /* Return a zero length.  */
        return(0);
    }

    if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES)
    {

        temp = buffer_ptr[1] & 0x7F;

        /* Determine if a two byte length is present.  */
        if (temp == 2)
        {

            /* Check the buffer length.  */
            if (buffer_length < 5)
            {
                return(0);
            }

            /* Pickup the total length of the object string.  */
            total =  (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]);
    
            /* Pickup the first byte.  */
            byte =  buffer_ptr[4];
    
            /* Save the pointer to the first byte.  */
            saved_ptr =  &buffer_ptr[4];
    
            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 4;
    
            /* Initialize the length.  */
            length =  4;
        }
        else if (temp == 1)
        {

            /* Pickup the total length of the object string.  */
            total =  buffer_ptr[2];
    
            /* Pickup the first byte.  */
            byte =  buffer_ptr[3];
    
            /* Save the pointer to the first byte.  */
            saved_ptr =  &buffer_ptr[3];
    
            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 3;
    
            /* Initialize the length.  */
            length =  3;
        }
        else
        {

            /* This is out of range or null. Invalid SNMP sequence. */
            return(0);
        }
    }
    else
    {

        /* Otherwise, assume one byte. */

        /* Pickup the total length of the object string.  */
        total =  (UINT) buffer_ptr[1];

        /* Check for invalid data size */
        if ((INT)total > (buffer_length - 1))
        {
            /* Indicate an invalid request is received. */
            return 0;
        }

        /* Pickup the first byte.  */
        byte =  buffer_ptr[2];

        /* Save the index.  */
        saved_ptr =  &buffer_ptr[2];

        /* Move the buffer pointer forward.  */
        buffer_ptr =  buffer_ptr + 2;

        /* Initialize the length.  */
        length =  2;
    }

    /* Save the original byte.  */
    saved_byte =  byte;

    /* Calculate the first two characters of object string.  */
    if (byte >= 80)
    {

        /* This form starts with 2 as the first identifier.  */
        *object_string++ =  '2';
    
        /* Increment the string length.  */
        string_length++;

        /* Adjust the byte.  */
        byte = (UCHAR)(byte - 80);
    }
    else if (byte >= 40)
    {
    
        /* This form starts with 1 as the first identifier.  */
        *object_string++ =  '1';

        /* Increment the string length.  */
        string_length++;
    
        /* Adjust the byte.  */
        byte = (UCHAR)(byte - 40);
    }
    else
    {

        /* This form starts with 0 as the first identifier.  */
        *object_string++ =  '0';

        /* Increment the string length.  */
        string_length++;
    }

    /* Always place a '.'.  */
    *object_string++ =  '.';

    /* Increment the string length.  */
    string_length++;

    /* Determine if the second identifier is legal.  */
    if (byte & NX_SNMP_ANS1_MULTI_BYTES)
    {
    
        /* Second identifier too large, return a zero length.  */
        return(0);
    }

    /* Write the byte back. */
    buffer_ptr[0] =  byte;

    /* Loop to pickup the remaining characters in the object string.  */
    while (total)
    {

        /* Move the buffer pointer forward.  */
        byte =  *buffer_ptr++;

        /* Decrement the total.  */
        total--;

        /* Increment the length.  */
        length++;

        /* Determine if the next byte has the additional bytes 
           bit set (BIT 7).  */
        if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0)
        {

            /* The specified sequence value is less than 128 and is actually in this byte!  */
            value =  (UINT) byte;
        }
        else
        {

            /* Otherwise, we have a more complicated value that we must loop through 
               to calculate.  */

            /* Loop to calculate how many bytes there are representing the value.  */
            i = 0;
            multiply =  128;
            while (buffer_ptr[i] & NX_SNMP_ANS1_MULTI_BYTES)
            {

                /* Increment count.  */
                i++;

                /* Adjust the multiplier. */
                multiply =  multiply * 128;
            }

            /* Determine if the count is reasonable.  */
            if (i > 3)
            {

                /* Restore the saved byte.  */
                *saved_ptr =  saved_byte;

                /* Nope, too big!  */
                return(0);
            }

            /* Loop to calculate the value.  */
            do
            {

                /* Pickup the number of bytes required to represent this value.  */
                temp =  (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES);

                /* Calculate the temporary value.  */
                temp =  temp * multiply;

                /* Calculate total value.  */
                value =  value + temp;
                
                /* Adjust the multiply value.  */
                multiply =  multiply/128;
                
                /* Pickup next byte.  */
                byte =  *buffer_ptr++;

                /* Decrement the total.  */
                if (total == 0)
                {
                
                    /* Restore the saved byte.  */
                    *saved_ptr =  saved_byte;

                    return(0);
                }
                else
                    total--;

                /* Increment the length.  */
                length++;

            } while (byte & NX_SNMP_ANS1_MULTI_BYTES);

            /* Add in the remainder.  */
            temp =  (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES);
            value =  value + temp;
        }

        /* Loop to convert value into ASCII.  */
        size =  0;
        do
        {

            /* Shift the current digits over one.  */
            for (i = size; i != 0; i--)
            {

                /* Move each digit over one place.  */
                object_string[i] =  object_string[i-1];
            }

            /* Compute the next decimal digit.  */
            byte =  (UCHAR) (value % 10);

            /* Update the input number.  */
            value =  value / 10;

            /* Store the new digit in ASCII form.  */
            object_string[0] =  (UCHAR)(byte + 0x30);

            /* Increment the size.  */
            size++;

            /* Increment the string length.  */
            string_length++;

            /* Determine if the length is too long.  */
            if (string_length >= NX_SNMP_MAX_OCTET_STRING)
            {
            
                /* String is too long.  */
                
                /* Null-terminate the string.  */
                *object_string =  NX_NULL;
                
                /* Return the length.  */
                return(length);
            }

        } while ((size < 10) && (value));

        /* Adjust the object string.  */
        object_string =  object_string + size;

        /* Determine if there are more tokens. */
        if (total)
        {

            /* Still more nodes, place a dot in the string.  */
            *object_string++ =  '.';

            /* Increment the string length.  */
            string_length++;

            /* Determine if the length is too long.  */
            if (string_length >= NX_SNMP_MAX_OCTET_STRING)
            {
            
                /* String is too long.  */
                
                /* Null-terminate the string.  */
                object_string--;
                *object_string =  NX_NULL;
                
                /* Return the length.  */
                return(length);
            }
        }
    }

    /* Restore the saved byte.  */
    *saved_ptr =  saved_byte;

    /* NULL-terminate the object string.  */
    *object_string =  NX_NULL;

    /* Return the length of the ANS1 string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_id_set                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function converts the ASCII representation of the object into  */ 
/*    ASN.1 format and then places it in the ASN.1 buffer.                */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    object_string                         Object string in ASCII        */
/*    buffer_end                            End of ASN.1 buffer for error */
/*                                            checking                    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              SNMP v1 trap send             */ 
/*    _nx_snmp_agent_trapv2_send            SNMP v2 trap send             */ 
/*    _nx_snmp_agent_trapv3_send            SNMP v3 trap send             */ 
/*    _nx_snmp_utility_object_data_set      Object data set               */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_object_id_set(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end)
{

UINT    length;
UINT    i;
ULONG   value;
UCHAR   *length_ptr;
UCHAR   encoding_started;
UINT    object_string_length;


    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* Check object string length.  */
    if (_nx_utility_string_length_check((CHAR*)object_string, &object_string_length, (UINT)(buffer_end - buffer_ptr)))
        return(0);

    /* Set the OBJECT byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_OBJECT_ID;

    /* Remember length pointer.  */
    length_ptr =  buffer_ptr;

    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* Set the length byte to zero for now.  */
    *buffer_ptr++ =  0;

    /* Check object string length.  */
    if (object_string_length < 2)
        return(0);

    /* Determine if the object string is legal.  */
    if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) ||
         (object_string[1] != '.'))
    {
        
        /* Invalid object ID.  */
        return(0);
    }

    /* Calculate the value of the second identifier.  */
    i =  2;
    value =  0;

    while ((object_string[i] != '.') && (object_string[i] != NX_NULL))
    {

        /* Compute the value.  */
        value =  (value * 10) + ((ULONG) (object_string[i] - 0x30));

        /* Move to the next character.  */
        i++;
    }

    if (object_string[i] == '.')
    {
        /* Move to the next character.  */
        i++;
    }
    
    /* The second identifier must be less that 128.  */
    if (value >= 128)
    {
    
        /* Invalid object ID.  */
        return(0);
    }

    /* Now determine how to set the first byte of the object ID.  */
    if (object_string[0] == '1')
    {
        
        /* Increment value by 40 per spec.  */
        value = value + 40;
    }
    else if (object_string[0] == '2')
    {
    
        /* Increment value by 40 per spec.  */
        value = value + 80;
    }

    /* Set the first byte, which is the combination of the first two bytes.  */
    *buffer_ptr++ =  (UCHAR) value;

    /* Set the length.  */
    length =  1;

    /* Process all the characters in the ID.  For now, the limit will be 128 characters in the
       ID specification string.  */
    while (object_string[i])
    {

        UCHAR    *value_ptr;
        UCHAR    byte0;
        ULONG    mod_value;

        /* Initialize the encoding started flag.  */ 
        encoding_started =  NX_FALSE;

        /* Pickup the next value.  */
        value =  0;
        while ((object_string[i] != '.') && (object_string[i] != NX_NULL))
        {

            /* Compute the value.  */
            value =  (value * 10) + ((ULONG) (object_string[i] - 0x30));

            /* Move to the next character.  */
            i++;
        }

        /* At this point we have a value to store in the ID string.  */

        /* Determine if it is simple encoding.  */
        if (value < 128)
        {

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Place the value directly in the buffer.  */
            *buffer_ptr++ =  (UCHAR) value;

            /* Increment the length.  */
            length++;
        }
        else
        {

            /* Otherwise, we need to encode the numeric value such that it has
               more bytes to represent it.  */

            if (value/268435456)
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */
               
                mod_value = value/268435456;  /* (0x10000000) */
                
                value_ptr = (UCHAR *)(&mod_value);
                
                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;
              
                buffer_ptr++;
                                
                /* Update the value.  */
                value =  value % 268435456;

                /* Increment the length.  */
                length++;
                
                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value/2097152) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */

                mod_value = value/2097152;  /* (0x10000000) */

                value_ptr = (UCHAR *)(&mod_value);

                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;

                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 2097152;

                /* Increment the length.  */
                length++;

                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value / 16384) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */
               
                mod_value = value/16384;  /* (0x10000000) */
                
                value_ptr = (UCHAR *)(&mod_value);
                
                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;
              
                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 16384;

                /* Increment the length.  */
                length++;


                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value /128) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */

                mod_value = value/128;  /* (0x100) */

                value_ptr = (UCHAR *)(&mod_value);

                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;

                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 128;

                /* Increment the length.  */
                length++;
            }

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Place the value directly in the buffer.  */
            *buffer_ptr++ =  (UCHAR) value;

            /* Increment the length.  */
            length++;
        }

        /* Determine if we are sitting on a dot.  */
        if (object_string[i] == '.')
            i++;
    }

    /* Update the length.  */
    length_ptr[0] =  (UCHAR) (length & 0xFF);

    /* Return the length plus the header information.  */
    return(length + 2);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_id_set_1byte                PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function converts the ASCII representation of the object into  */ 
/*    ASN.1 format and then places it in the ASN.1 buffer.                */ 
/*                                                                        */ 
/*    The difference with _nx_snmp_utility_object_id_set is that          */ 
/*    this uses only a single byte length field e.g. 0x30 xx instead of   */
/*    0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    object_string                         Object string in ASCII        */
/*    buffer_end                            End of ASN.1 buffer for error */
/*                                            checking                    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_object_id_set_1byte(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end)
{

UINT    length;
UINT    i;
ULONG   value;
UCHAR   *length_ptr;
UCHAR   encoding_started;


    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* Set the OBJECT byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_OBJECT_ID;

    /* Remember length pointer.  */
    length_ptr =  buffer_ptr;

    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* Set the length byte to zero for now.  */
    *buffer_ptr++ =  0;

    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* Determine if the object string is legal.  */
    if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) ||
         (object_string[1] != '.'))
    {
        
        /* Invalid object ID.  */
        return(0);
    }

    /* Calculate the value of the second identifier.  */
    i =  2;
    value =  0;

    while ((object_string[i] != '.') && (object_string[i] != NX_NULL))
    {

        /* Compute the value.  */
        value =  (value * 10) + ((ULONG) (object_string[i] - 0x30));

        /* Move to the next character.  */
        i++;
    }

    if (object_string[i] == '.')
    {
        /* Move to the next character.  */
        i++;
    }
    
    /* The second identifier must be less that 128.  */
    if (value >= 128)
    {
    
        /* Invalid object ID.  */
        return(0);
    }

    /* Now determine how to set the first byte of the object ID.  */
    if (object_string[0] == '1')
    {
        
        /* Increment value by 40 per spec.  */
        value = value + 40;
    }
    else if (object_string[0] == '2')
    {
    
        /* Increment value by 40 per spec.  */
        value = value + 80;
    }

    /* Set the first byte, which is the combination of the first two bytes.  */
    *buffer_ptr++ =  (UCHAR) value;

    /* Set the length.  */
    length =  1;

    /* Process all the characters in the ID.  For now, the limit will be 128 characters in the
       ID specification string.  */
    while (object_string[i])
    {

        UCHAR    *value_ptr;
        UCHAR    byte0;
        ULONG    mod_value;

        /* Initialize the encoding started flag.  */ 
        encoding_started =  NX_FALSE;

        /* Pickup the next value.  */
        value =  0;
        while ((object_string[i] != '.') && (object_string[i] != NX_NULL))
        {

            /* Compute the value.  */
            value =  (value * 10) + ((ULONG) (object_string[i] - 0x30));

            /* Move to the next character.  */
            i++;
        }

        /* At this point we have a value to store in the ID string.  */

        /* Determine if it is simple encoding.  */
        if (value < 128)
        {

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Place the value directly in the buffer.  */
            *buffer_ptr++ =  (UCHAR) value;

            /* Increment the length.  */
            length++;
        }
        else
        {

            /* Otherwise, we need to encode the numeric value such that it has
               more bytes to represent it.  */

            if (value/268435456)
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */
               
                mod_value = value/268435456;  /* (0x10000000) */
                
                value_ptr = (UCHAR *)(&mod_value);
                
                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;
              
                buffer_ptr++;
                  
                
                /* Update the value.  */
                value =  value % 268435456;

                /* Increment the length.  */
                length++;
                
                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value/2097152) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */
               
                mod_value = value/2097152;  /* (0x10000000) */
                
                value_ptr = (UCHAR *)(&mod_value);
                
                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;
              
                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 2097152;

                /* Increment the length.  */
                length++;

                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value / 16384) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */
               
                mod_value = value/16384;  /* (0x10000000) */
                
                value_ptr = (UCHAR *)(&mod_value);
                
                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;
              
                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 16384;

                /* Increment the length.  */
                length++;


                /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the 
                   next 128 divisor.  */
                encoding_started =  NX_TRUE;
            }

            if ((value /128) || (encoding_started == NX_TRUE))
            {

                /* Check for the end of the buffer.  */
                if (buffer_ptr >= buffer_end)
                    return(0);

                /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible),
                use an intermediate ULONG pointer. */

                mod_value = value/128;  /* (0x100) */

                value_ptr = (UCHAR *)(&mod_value);

                /* A UCHAR will not hold more than one byte. */
                byte0 = *(value_ptr);

                *buffer_ptr =  ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES;

                buffer_ptr++;
                
                /* Update the value.  */
                value =  value % 128;

                /* Increment the length.  */
                length++;
            }

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Place the value directly in the buffer.  */
            *buffer_ptr++ =  (UCHAR) value;

            /* Increment the length.  */
            length++;
        }

        /* Determine if we are sitting on a dot.  */
        if (object_string[i] == '.')
            i++;
    }

    /* Update the length.  */
    length_ptr[0] =  (UCHAR) (length & 0xFF);

    /* Return the length plus the header information.  */
    return(length + 2);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_data_get                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object data from the supplied ASN.1     */ 
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    object_data                           Pointer to place object data  */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_id_get        Get object ID                 */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_object_data_get(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, INT buffer_length)
{


UINT    i;
UINT    length;
LONG    data;
UINT    total;
CHAR    byte;
LONG    temp = 0;
USHORT  tlv_type, tlv_tag_class;
UCHAR   *tlv_data;
UCHAR   *work_ptr;
UINT    status;


    /* Check the buffer length.  */
    if (buffer_length < 1)
    {
        return(0);
    }

    work_ptr = buffer_ptr;

    /* First, pickup the request byte.  */
    byte =  (CHAR)(*buffer_ptr);

    /* Clear several value words.  */
    object_data -> nx_snmp_object_data_msw =   0;
    object_data -> nx_snmp_object_data_lsw =   0;

    /* Determine if a NULL is present.  */
    if (byte == NX_SNMP_ANS1_NULL)
    {

        /* Return NULL values in the input object, and set length to 2 (0x05 00).  */
        object_data -> nx_snmp_object_data_type =  NX_SNMP_ANS1_NULL;
        object_data -> nx_snmp_object_data_msw =   0;
        return(2);
    }

    /* Determine if the object is a standard type.  */
    else if ((byte == NX_SNMP_ANS1_OCTET_STRING) || (byte == NX_SNMP_ANS1_INTEGER) || 
             (byte == NX_SNMP_ANS1_TIME_TICS) || (byte == NX_SNMP_ANS1_GAUGE) || 
             (byte == NX_SNMP_ANS1_COUNTER) || (byte == NX_SNMP_ANS1_COUNTER64) || 
             (byte == NX_SNMP_IP_ADDRESS) || (byte == NX_SNMP_ANS1_NSAP_ADDRESS))
    {

        /* Standard object type.  */

        /* Check the buffer length.  */
        if (buffer_length < 3)
        {
            return(0);
        }

        /* If this is an integer, determine if we have a negative number (msb is set). */
        if ((*buffer_ptr == NX_SNMP_ANS1_INTEGER) && (*(buffer_ptr + 2) & 0x80))
        {

            /* This only applies if short form (size of length =1), not long form (size of length field > 1 byte) */
            if (((*(buffer_ptr + 1) & 0x80)== 0))
                temp = -1;

            /* We can only check the sign for long form data after we compute the length of length field below */
        }

        /* Update the object with the data type. */
        object_data -> nx_snmp_object_data_type = (UINT)byte;

        /* Extract the length of the length field and tag class. This sill update the pointer past the type
         * and length fields to the actual data.   */
        status = _nx_snmp_utility_tlv_block_parse(work_ptr, buffer_length, &tlv_type, &tlv_tag_class,  (ULONG *)(&total), &tlv_data, (ULONG *)(&length));

        if (status)
        {
            return 0;
        }
        
        work_ptr = tlv_data;

        /* Initialize working data.  */
        data =  temp;
        object_data -> nx_snmp_object_octet_string_size =  0;

        i = 0;

        /* handle the special case of a leading zero e.g.  00 DD 2F C9 CE 69 52 74 8D where total is 9 */
         if ((total == 9) &&  (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING))
         {
             /* Skip the first byte and decrement total */
             work_ptr++;
             total = total - 1;
         }


         /* Loop through the remaining request length bytes.  */
        while (i < total)
        {

            /* Pickup next byte.  */
            byte =  (CHAR)(*work_ptr++);

            /* Determine the type of the data.  */
            if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING)
            {

                /* Check for string size.  */
                if ((i) >= NX_SNMP_MAX_OCTET_STRING)
                {
                    return(0);
                }

                /* Copy byte into the string.  */
                object_data -> nx_snmp_object_octet_string[i] =  (UCHAR)byte;

                /* Increment the length.  */
                object_data -> nx_snmp_object_octet_string_size++;
            }
            else
            {

                /* Compute the request id based on the next value.  */
                data =  (data << 8) | ((LONG) (0x000000FF & byte));
            }

            /* Increment the length.  */
            length++;

             i++;

            /* If we are dealing with a 64 bit number, store the rest (least) significant bytes in lsw. */
            if ((i == 4) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64))
            {
                object_data -> nx_snmp_object_data_msw =  data;

                data = 0x0;

                /* Finish the rest of the data into lsw */
                while(i < total)
                {
                    /* Pickup next byte.  */
                    byte =  (CHAR)(*work_ptr++);

                    /* Compute the request id based on the next value.  */
                    data =  (data << 8) | ((LONG) (0x000000FF & byte));

                    i++;
                }

                object_data -> nx_snmp_object_data_lsw =  data;
            }
        }

        /* If dealing with a 32 bit data type or less, store the data to msw */
        if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64)
        {
            object_data -> nx_snmp_object_data_msw =  data;
        }
        else
        {
            /* Otherwise (e.g. this is a 64 bit data type) store the least significant bytes in the lsw */
            object_data -> nx_snmp_object_data_lsw =  data;
        }
        /* Null terminate the data string.  */
        if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING)
        {

            /* Null terminate string.  */
            if ((i > 0) && (i < NX_SNMP_MAX_OCTET_STRING))
            {
                object_data -> nx_snmp_object_octet_string[i] =  NX_NULL;
            }
        }

        /* Return the length of the request id string.  */
        return(length);
    }
    else if (byte == NX_SNMP_ANS1_OBJECT_ID)
    {

        /* Setup the data type.  */
        object_data -> nx_snmp_object_data_type =  (UINT)byte;

        /* Convert the object ID to a string.  */
        length =  _nx_snmp_utility_object_id_get(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_length);

        /* Return length of the object id.  */
        return(length);
    }

    /* Error; return zero length.  */
    return(0);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_data_set                    PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the object data and then places it in the   */ 
/*    ASN.1 buffer.                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    object_data                           Object data structure         */
/*    buffer_end                            End of ASN.1 buffer for error */
/*                                            checking                    */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_snmp_utility_object_id_set        Set object ID                 */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Send SNMP v1 Trap             */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 Trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 Trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_object_data_set(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, UCHAR *buffer_end)
{

UINT    i;
UINT    length;
UINT    data_msw;
UINT    data_lsw;


    /* Process relative to the type of request.  */

    /* See if the request is a NULL.  */
    if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NULL) ||
        (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_OBJECT) ||
        (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_INSTANCE) ||
        (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW))
    {

        /* Check for the end of the buffer.  */
        if ((buffer_ptr + 2) >= buffer_end)
            return(0);

        /* Set the NULL type byte.  */
        *buffer_ptr++ =  (UCHAR) object_data -> nx_snmp_object_data_type;
        *buffer_ptr   =  0;

        /* Set the length. */
        length =  2;
    }

    /* See if the request is an INTEGER.  */
    else if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_INTEGER) ||
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_UINTEGER32) || 
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_TIME_TICS) || 
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_GAUGE) || 
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER) || 
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64) || 
             (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS) ||
             (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NSAP_ADDRESS))
    {


        /* Check for the end of the buffer.  */
        if (buffer_ptr >= buffer_end)
            return(0);

        /* Set the type byte.  */
        *buffer_ptr++ =  (UCHAR)object_data -> nx_snmp_object_data_type;

        /* Pickup the data most significant word.  */
        data_msw =  (UINT)(object_data -> nx_snmp_object_data_msw);

        /* Pickup the data least significant word.  */
        data_lsw =  (UINT)(object_data -> nx_snmp_object_data_lsw);

        /* Determine the size of the encoding.  */
        if (((data_msw & 0xFF000000) || (data_msw & 0x00800000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 9) >= buffer_end)
                return(0);

            /* Four bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 8);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_lsw & 0xFF);

            /* Update the length.  */
            length =  10;
            return(length);
        }
        else if (((data_msw & 0x00FF0000) || (data_msw & 0x00008000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 8) >= buffer_end)
                return(0);

            /* Three bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 7);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_lsw & 0xFF);

            /* Update the length.  */
            length =  9;
            return(length);
        }
        else if (((data_msw & 0x0000FF00) || (data_msw & 0x00000080)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 7) >= buffer_end)
                return(0);

            /* Two bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 6);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_lsw & 0xFF);

            /* Update the length.  */
            length =  8;
            return(length);
        }
        else if (((data_msw & 0x000000FF) || (data_lsw & 0x80000000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 6) >= buffer_end)
                return(0);

            /* One byte is required.  */
            *buffer_ptr++ =  ((UCHAR) 5);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) (data_msw & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_lsw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_lsw & 0xFF);

            /* Update the length.  */
            length =  7;
            return(length);
        }
        else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)
        {

            /* Make the least significant word the most significant to use the normal integer processing below.  */
            data_msw =  data_lsw;
        }

        /* Determine the size of the encoding.  */
        if ((data_msw & 0xFF000000) || (data_msw & 0x00800000) || (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 5) >= buffer_end)
                return(0);

            /* Four bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 4);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 24) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);

            /* Update the length.  */
            length =  6;
        }
        else if ((data_msw & 0x00FF0000) || (data_msw & 0x00008000))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 4) >= buffer_end)
                return(0);

            /* Three bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 3);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 16) & 0xFF);
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);

            /* Update the length.  */
            length =  5;
        }
        else if ((data_msw & 0x0000FF00) || (data_msw & 0x00000080))
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 3) >= buffer_end)
                return(0);

            /* Two bytes are required.  */
            *buffer_ptr++ =  ((UCHAR) 2);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) ((data_msw >> 8)  & 0xFF);
            *buffer_ptr++ =  (UCHAR)  (data_msw & 0xFF);

            /* Update the length.  */
            length =  4;
        }
        else
        {

            /* Check for the end of the buffer.  */
            if ((buffer_ptr + 2) >= buffer_end)
                return(0);

            /* One byte is required.  */
            *buffer_ptr++ =  ((UCHAR) 1);

            /* Set the value in successive bytes.  */
            *buffer_ptr++ =  (UCHAR) (data_msw & 0xFF);

            /* Update the length.  */
            length =  3;
        }
    }

    /* See if the request is an octet string. Note that this includes the IPv6 address type.  */
    else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING)
    {

        /* Check for the end of the buffer.  */
        if (buffer_ptr >= buffer_end)
            return(0);

        /* Set the OCTET type byte.  */
        *buffer_ptr++ =  NX_SNMP_ANS1_OCTET_STRING;

        /* Check for the end of the buffer.  */
        if (buffer_ptr >= buffer_end)
            return(0);

        /* Determine if a two byte length is required.  */
        if (object_data -> nx_snmp_object_octet_string_size >= 128)
        {

            /* A two byte length is required.  */

            /* Set the two byte length.  */
            *buffer_ptr++ =  0x82;

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Set the first byte of the length.  */
            *buffer_ptr++ =  (UCHAR) (object_data -> nx_snmp_object_octet_string_size >> 8);

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Set the second byte of the length.  */
            *buffer_ptr++ =  (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF);

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Set the length to represent the 4 byte header.  */
            length =  4;
        }
        else
        {

            /* Set the length byte.  */
            *buffer_ptr++ =  (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF);

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Set the length to represent the 2 byte header.  */
            length =  2;
        }

        /* Loop to process the string.  */
        i =  0;
        while (i < object_data -> nx_snmp_object_octet_string_size)
        {

            /* Check for the end of the buffer.  */
            if (buffer_ptr >= buffer_end)
                return(0);

            /* Place octet string into buffer.  */
            *buffer_ptr++ =  object_data -> nx_snmp_object_octet_string[i++];
        }

        /* Account for the leading bytes in the length.  */
        length =  length + i;
    }
    
    else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OBJECT_ID)
    {

        /* Call the object set routine.  */
        length = _nx_snmp_utility_object_id_set(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_end);
    }
    else
    {

        /* Unhandled, return an error by setting length to 0.  */
        length =  0;
    }

    /* Return the length.  */
    return(length);   
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_octet_get                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the octet string from the supplied ASN.1    */ 
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    octet_string                          Pointer to destination for    */ 
/*                                            the octet string            */ 
/*    max_octet_length                      Size of octet string buffer   */
/*    octet_length                          Pointer to length for octet   */ 
/*                                            string                      */ 
/*    buffer_length                         Size of input buffer          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_octet_get(UCHAR *buffer_ptr, UCHAR *octet_string, UINT max_octet_length, UINT *octet_length, INT buffer_length)
{

UINT    i;
UINT    length;
UINT    total;


    /* Buffer size must be at least 2 bytes. */
    if (buffer_length < 2)
    {
        return(0);
    }

    /* Set the octet length to zero.  */
    *octet_length =  0;

    /* First see if the ANS1 string type is present.  */
    if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING)
    {

        /* Return a zero length.  */
        return(0);
    }

    /* Determine if a two byte length is present.  */
    if (*(buffer_ptr + 1) & NX_SNMP_ANS1_MULTI_BYTES)
    {

    UINT temp = *(buffer_ptr + 1) & 0x7F;

        if (temp == 2)
        {

            /* A two byte length is present.  */

            /* Check the buffer length.  */
            if (buffer_length < 4)
            {
                return(0);
            }

            /* Pickup the length.  */
            total =  (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]);
    
            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 4;
    
            /* Initialize the length.  */
            length =  4;
        }
        else if (temp == 1)
        {

            /* Check the buffer length.  */
            if (buffer_length < 3)
            {
                return(0);
            }

            /* Otherwise, pickup the total length of the octet string.  */
            total =  (UINT) buffer_ptr[2];

            /* Move the buffer pointer forward.  */
            buffer_ptr =  buffer_ptr + 3;

            /* Initialize the length.  */
            length =  3;
        }
        else
        {

            /* Invalid sequence. Too big or null size type. */
            return(0);
        }
    }
    else
    {

        /* Otherwise, assume 1 byte. Pickup the total length of the octet string.  */
        total =  (UINT) buffer_ptr[1];

        /* Move the buffer pointer forward.  */
        buffer_ptr =  buffer_ptr + 2;

        /* Initialize the length.  */
        length =  2;
    }

    /* Check for invalid buffer size. */
    if ((INT)(length + total) > buffer_length)
    {
        /* Indicate an invalid request or packet is received. */
        return 0;
    }

    /* Determine if the octet string is too large.  */
    if (total > max_octet_length)
    {
    
        /* Yes, the octet string is too large. Return an error.  */
        return(0);
    }    

    /* Loop to pickup the remaining characters in the community string.  */
    for (i = 0; i < total; i++)
    {

        /* Move character from buffer into community string.  */
        *octet_string++ =  *buffer_ptr++;

        /* Adjust the length.  */
        length++;
    }

    /* return the length of the octet string.  */
    *octet_length =  total;

    /* Return the length of the ANS1 string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_octet_set                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the supplied octet string into the ASN.1       */ 
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    octet_string                          Pointer to octet string       */
/*    octet_length                          Length of the octet string    */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_octet_set(UCHAR *buffer_ptr, UCHAR *octet_string, UINT octet_length, UCHAR *buffer_end)
{

UINT    i;
UINT    header_size;


    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* First, set the OCTET byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_OCTET_STRING;  

    /* Check for a length greater than the maximum.  */
    if (octet_length > NX_SNMP_MAX_OCTET_STRING)
    {

        /* Error, octet string is too large.  */
        return(0);
    }

    /* Determine if a two byte length is required.  */
    if (octet_length >= 128)
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < (3 + octet_length))
            return(0);

        /* Set the two byte length flag.  */
        *buffer_ptr++ =  (UCHAR) 0x82;

        /* Set the first length byte.  */
        *buffer_ptr++ =  (UCHAR) (octet_length >> 8);

        /* Set the second length byte.  */
        *buffer_ptr++ =  (UCHAR) (octet_length & 0xFF);

        /* Set the header size. */
        header_size =  4;
    }
    else
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < (1 + octet_length))
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) octet_length;

        /* Set the header size. */
        header_size =  2;
    }

    /* Loop to store rest of the community string.  */
    for (i = 0; i < octet_length; i++)
    {

        /* Store the SNMP octet string.  */
        *buffer_ptr++ =  (UCHAR) octet_string[i];
    }

    /* Return the length of the community string.  */
    return(octet_length+header_size);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_sequence_get                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the ASN.1 sequence from the supplied ASN.1  */ 
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    sequence_value                        Pointer to destination for    */
/*                                            the sequence value          */ 
/*    buffer_length                         Size of buffer data           */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry           SNMP Agent's thread entry     */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_sequence_get(UCHAR *buffer_ptr, UINT *sequence_value, INT buffer_length)
{

UINT    i;
UINT    length;
UINT    value;
UINT    total;
UCHAR   byte;


    /* Buffer size must be at least 2 bytes. */
    if (buffer_length < 2)
    {
        return(0);
    }

    /* First, pickup the sequence byte.  */
    byte =  *buffer_ptr++;

    /* Determine if the byte is a sequence byte (0x30).  */
    if (byte != NX_SNMP_ANS1_SEQUENCE)
    {

        /* Error, not a sequence byte, return a NULL.  */
        *sequence_value =  0;
        return(0);
    }

    /* Otherwise, we have a valid sequence byte.  */

    /* Pickup next byte.  */
    byte =  *buffer_ptr++;

    /* Initialize the length of the sequence field to 2. */
    length =  2;

    /* Determine if the next byte has the additional bytes 
       bit set (BIT 7).  */
    if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0)
    {

        /* The specified sequence value is less than 128 and is actually in this byte!  */
        *sequence_value =  (UINT) byte;

        /* Return the actual length of the ANS1 sequence string.  */
        return(length);
    }

    /* Otherwise, we have a more complicated sequence length that we must loop through 
       to calculate the actual sequence length.  */

    /* Pickup the number of bytes required to represent the sequence length.  */
    total =  (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES);

    /* Check for invalid buffer size. */
    if ((INT)(length + total) > buffer_length)
    {
        /* Indicate an invalid request or packet is received. */
        return 0;
    }

    value =  0;

    /* Loop through the remaining sequence bytes.  */
    for (i = 0; i < total; i++)
    {

        /* Pickup next byte.  */
        byte =  *buffer_ptr++;

        /* Compute the sequence based on the next value.  */
        value =  (value << 8) | ((UINT) byte);

        /* Increment the length.  */
        length++;
    }

    /* Return the calculated sequence value.  */
    *sequence_value =  value;

    /* Return the length of the sequence string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_sequence_set                       PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the sequence number into the ASN.1             */ 
/*    buffer.                                                             */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    sequence_value                        Sequence value                */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Send SNMP v1 trap             */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_sequence_set(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end)
{

    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 4)
        return(0);

    /* First, set the sequence byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_SEQUENCE;  

    /* Next set the continue bit to force two additional bytes for length.  */
    *buffer_ptr++ =  ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES;

    /* Store the MSB.  */
    *buffer_ptr++ =  (UCHAR) ((sequence_value >> 8) & 0xFF);

    /* Store the LSB.  */
    *buffer_ptr =  (UCHAR) (sequence_value & 0xFF);

    /* Return the length of the sequence string.  */
    return(4);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_sequence_set_1byte                 PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the sequence number into the ASN.1             */ 
/*    buffer.  The difference with  _nx_snmp_utility_sequence_set is that */ 
/*    this uses only a single byte length field e.g. 0x30 xx instead of   */
/*    0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    sequence_value                        Sequence value                */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
 
UINT  _nx_snmp_utility_sequence_set_1byte(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end)
{

    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 2)
        return(0);

    /* First, set the sequence byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_SEQUENCE;  

    /* Store the value.  */
    *buffer_ptr =  (UCHAR) (sequence_value & 0xFF);

    /* Return the length of the sequence string.  */
    return(2);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_request_id_get                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the ASN.1 request ID from the supplied      */ 
/*    ASN.1 buffer.                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    request_id                            Pointer to destination for    */
/*                                            the request ID              */ 
/*    buffer_length                         Size of buffer                */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_request_id_get(UCHAR *buffer_ptr, ULONG *request_id, INT buffer_length)
{

UINT    i;
UINT    length;
ULONG   value;
UINT    total;
UCHAR   byte;


    /* Buffer size must be at least 2 bytes. */
    if (buffer_length < 2)
    {
        return(0);
    }

    /* First, pickup the request byte.  */
    byte =  *buffer_ptr++;

    /* Determine if the byte is a valid SNMP request type.  */
    if (byte != NX_SNMP_ANS1_INTEGER)
    {

        /* Error, not request id, return a NULL.  */
        *request_id =    0;
        return(0);
    }

    /* Otherwise, we have a valid request id.  */

    /* Pickup the ANS1 length byte.  */
    total =  (UINT) *buffer_ptr++;

    /* Initialize the length of the request field to 2. */
    length =  2;

    /* Check the length specified in the buffer against buffer size. */
    if ((INT)(length + total) > buffer_length)
    {
        *request_id = 0;
        return(0);
    }

    /* Initialize working request length.  */
    value =  0;

    /* Loop through the remaining request length bytes.  */
    for (i = 0; i < total; i++)
    {

        /* Pickup next byte.  */
        byte =  *buffer_ptr++;

        /* Compute the request id based on the next value.  */
        value =  (value << 8) | ((ULONG) byte);

        /* Increment the length.  */
        length++;
    }

    /* Return the calculated request id.  */
    *request_id =  value;

    /* Return the length of the request id string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_request_id_set                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the request ID into the ASN.1 buffer.          */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    request_id                            Request ID                    */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_request_id_set(UCHAR *buffer_ptr, ULONG request_id, UCHAR *buffer_end)
{

UINT    length;


    /* Check for the end of the buffer.  */
    if (buffer_ptr >= buffer_end)
        return(0);

    /* First, set the INTEGER byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_INTEGER;  

    /* Determine how big the ID is.  */
    if ((request_id & 0xFF000000UL) || (request_id & 0x00800000))
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < 5)
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) 4;

        /* Set the request ID in successive bytes.  */
        *buffer_ptr++ =  (UCHAR) ((request_id >> 24) & 0xFF);
        *buffer_ptr++ =  (UCHAR) ((request_id >> 16) & 0xFF);
        *buffer_ptr++ =  (UCHAR) ((request_id >> 8)  & 0xFF);
        *buffer_ptr++ =  (UCHAR)  (request_id & 0xFF);

        /* Update the length.  */
        length =  6;
    }
    else if ((request_id & 0x00FF0000UL) || (request_id & 0x00008000))
    {
        
        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < 4)
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) 3;

        /* Set the request ID in successive bytes.  */
        *buffer_ptr++ =  (UCHAR) ((request_id >> 16) & 0xFF);
        *buffer_ptr++ =  (UCHAR) ((request_id >> 8)  & 0xFF);
        *buffer_ptr++ =  (UCHAR)  (request_id & 0xFF);

        /* Update the length.  */
        length =  5;
    }
    else if ((request_id & 0x0000FF00UL) || (request_id & 0x00000080))
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < 3)
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) 2;

        /* Set the request ID in successive bytes.  */
        *buffer_ptr++ =  (UCHAR) ((request_id >> 8)  & 0xFF);
        *buffer_ptr++ =  (UCHAR)  (request_id & 0xFF);

        /* Update the length.  */
        length =  4;
    }
    else
    {

        /* Check for the end of the buffer.  */
        if ((UINT)(buffer_end - buffer_ptr) < 2)
            return(0);

        /* Next set the length byte.  */
        *buffer_ptr++ =  (UCHAR) 1;

        /* Set the request ID in successive bytes.  */
        *buffer_ptr++ =  (UCHAR)  (request_id & 0xFF);

        /* Update the length.  */
        length =  3;
    }

    /* Return the length of the request ID.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_request_type_get                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the ASN.1 request type from the supplied    */ 
/*    ASN.1 buffer.                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    request_type                          Pointer to destination for    */
/*                                            the request type            */ 
/*    request_length                        Pointer to destination for    */ 
/*                                            the request length          */ 
/*    buffer_length                         Size of input buffer          */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_request_type_get(UCHAR *buffer_ptr, UINT *request_type, UINT *request_length, INT buffer_length)
{

UINT    i;
UINT    length;
UINT    value;
UINT    total;
UCHAR   byte;


    /* Buffer size must be at least 2 bytes. */
    if (buffer_length < 2)
    {
        return(0);
    }

    /* First, pickup the request byte.  */
    byte =  *buffer_ptr++;

    /* Determine if the byte is a valid SNMP request type.  */
    if ((byte < NX_SNMP_ANS1_SEQUENCE) || (byte > NX_SNMP_ANS1_TRAP2_REQUEST))
    {

        /* Error, not request, return a NULL.  */
        *request_type =    0;
        *request_length =  0;
        return(0);
    }

    /* Otherwise, we have a valid request.  */

    /* Store the request in the destination.  */
    *request_type =  (UINT) byte;

    /* Pickup next byte.  */
    byte =  *buffer_ptr++;

    /* Initialize the length of the request field to 2. */
    length =  2;

    /* Determine if the next byte has the additional bytes 
       bit set (BIT 7).  */
    if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0)
    {

        /* The specified request length is less than 128 and is actually in this byte!  */
        *request_length =  (UINT) byte;

        /* Return the actual length of the ANS1 request string.  */
        return(length);
    }

    /* Otherwise, we have a more complicated request length that we must loop through 
       to calculate the actual length.  */

    /* Pickup the number of bytes required to represent the request length.  */
    total =  (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES);

    if ((INT)(length + total) > buffer_length)
    {
        /* Error, invalid request, return a NULL.  */
        *request_type =    0;
        *request_length =  0;
        return(0);
    }

    /* Initialize working request length.  */
    value =  0;

    /* Loop through the remaining request length bytes.  */
    for (i = 0; i < total; i++)
    {

        /* Pickup next byte.  */
        byte =  *buffer_ptr++;

        /* Compute the request length based on the next value.  */
        value =  (value << 8) | ((UINT) byte);

        /* Increment the length.  */
        length++;
    }

    /* Return the calculated request length.  */
    *request_length =  value;

    /* Return the length of the request string.  */
    return(length);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_request_type_set_1byte             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the request type into the ASN.1 buffer. It is  */
/*    intended for small requests whose size value can fit into one byte. */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    request_type                          Request type                  */ 
/*    request_length                        Request length                */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Send SNMP v1 trap             */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_request_type_set_1byte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end)
{


    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 2)
        return(0);

    /* First, set the request type byte.  */
    *buffer_ptr++ =  (UCHAR) request_type;  

    /* Store the request_length.  */
    *buffer_ptr =  (UCHAR) (request_length & 0xFF);

    return 2;

}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_request_type_set_multibyte         PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the request type into the ASN.1 buffer. It is  */
/*    intended for large requests whose size value requires more than one */
/*    byte, e.g. A2 82 xx yy. For get, getnext requests, and report and   */
/*    trap responses, use _nx_snmp_utility_request_type_set_1byte.        */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    request_type                          Request type                  */ 
/*    request_length                        Request length                */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_request_type_set_multibyte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end)
{

    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 4)
        return(0);

    /* First, set the request type byte.  */
    *buffer_ptr++ =  (UCHAR) request_type;  

    /* Set the continue bit to force two additional bytes for length.  */
    *buffer_ptr++ =  ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES;

    /* Store the MSB.  */
    *buffer_ptr++ =  (UCHAR) ((request_length >> 8) & 0xFF);

    /* Store the LSB.  */
    *buffer_ptr =  (UCHAR) (request_length & 0xFF);

    return 4;
}



/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_version_get                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function retrieves the SNMP version from the supplied          */ 
/*    ASN.1 buffer.                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    snmp_version                          Pointer to destination for    */
/*                                            the snmp_version            */ 
/*    buffer_length                         Size of buffer data           */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry           SNMP Agent's thread entry     */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_version_get(UCHAR *buffer_ptr, UINT *snmp_version, INT buffer_length)
{

    if (buffer_length < 3)
    {

        /* Clear the version.  */
        *snmp_version =  0;

        /* Return a zero length.  */
        return(0);
    }

    /* Determine if the version string is correct.  */
    if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) &&
        (buffer_ptr[1] == 1) &&
        ((buffer_ptr[2] == NX_SNMP_VERSION_1) || (buffer_ptr[2] == NX_SNMP_VERSION_2) ||
         (buffer_ptr[2] == NX_SNMP_VERSION_2C) || (buffer_ptr[2] == NX_SNMP_VERSION_3)))
    {

        /* Yes, the SNMP version string is correct.  */

        /* Return the version.  */
        *snmp_version =  (UINT) buffer_ptr[2];

        /* Return the length of the version string.  */
        return(3);
    }
    else
    {

        /* No, the SNMP version string is invalid.  */

        /* Clear the version.  */
        *snmp_version =  0;

        /* Return a zero length.  */
        return(0);
    }
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_utility_version_set                        PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the SNMP version into the ASN.1 buffer.        */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    buffer_ptr                            Pointer to ASN.1 buffer       */ 
/*    snmp_version                          SNMP version number           */ 
/*    buffer_end                            End of buffer                 */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    ASN.1 length                          Length of ASN.1 sequence, a   */ 
/*                                            value of zero implies error */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_trap_send              Send SNMP v1 trap             */ 
/*    _nx_snmp_agent_trapv2_send            Send SNMP v2 trap             */ 
/*    _nx_snmp_agent_trapv3_send            Send SNMP v3 trap             */ 
/*    _nx_snmp_version_1_process            Process SNMP v1 request       */ 
/*    _nx_snmp_version_2_process            Process SNMP v2 request       */ 
/*    _nx_snmp_version_3_report_send        Send SNMP v3 report           */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT  _nx_snmp_utility_version_set(UCHAR *buffer_ptr, UINT snmp_version, UCHAR *buffer_end)
{

    /* Check for the end of the buffer.  */
    if ((UINT)(buffer_end - buffer_ptr) < 3)
        return(0);

    /* First, set the INTEGER byte.  */
    *buffer_ptr++ =  NX_SNMP_ANS1_INTEGER;  

    /* Next set the length byte.  */
    *buffer_ptr++ =  (UCHAR) 1;

    /* Store the SNMP version.  */
    *buffer_ptr =  (UCHAR) (snmp_version & 0xFF);

    /* Return the length of the sequence string.  */
    return(3);
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_version_error_response                     PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function places the error information into the SNMP Manager's  */ 
/*    request packet and returns it to the manager.                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    packet_ptr                            Pointer to packet containing  */ 
/*                                            the original SNMP request   */ 
/*    request_type_ptr                      Pointer to place in ASN.1     */ 
/*                                            buffer for the request type */ 
/*    error_string_ptr                      Pointer to place in ASN.1     */ 
/*                                            buffer to place error info  */ 
/*    error_code                            Error code                    */ 
/*    error_index                           Error index                   */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_release                     Release the packet            */ 
/*    nx_udp_socket_send                    Send the UDP packet           */ 
/*    _nx_snmp_utility_error_info_set       Set the error information     */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process            SNMP v1 message processing    */ 
/*    _nx_snmp_version_2_process            SNMP v2 message processing    */ 
/*    _nx_snmp_version_3_process            SNMP v3 message processing    */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, 
                                      UCHAR *error_string_ptr, UINT error_code, UINT error_index)
{

UINT    status;
#ifndef NX_SNMP_DISABLE_V3
ULONG   temp;
#endif

    /* Increment the error counter.  */
    agent_ptr -> nx_snmp_agent_request_errors++;

    /* Determine which specific error counter to increment.  */
    switch(error_code)
    {
    case NX_SNMP_ERROR_TOOBIG:
        agent_ptr -> nx_snmp_agent_too_big_errors++;
        break;
    case NX_SNMP_ERROR_BADVALUE:
    case NX_SNMP_ERROR_WRONGVALUE:
    case NX_SNMP_ERROR_WRONGENCODING:
    case NX_SNMP_ERROR_WRONGTYPE:
    case NX_SNMP_ERROR_WRONGLENGTH:
    case NX_SNMP_ERROR_INCONSISTENTVALUE:
        agent_ptr -> nx_snmp_agent_bad_value_errors++; 
        break;
    case NX_SNMP_ERROR_NOSUCHNAME:
    case NX_SNMP_ERROR_NOACCESS:
    case NX_SNMP_ERROR_NOTWRITABLE:
    case NX_SNMP_ERROR_NOCREATION:
    case NX_SNMP_ERROR_INCONSISTENTNAME:
    case NX_SNMP_ERROR_AUTHORIZATION:
        agent_ptr -> nx_snmp_agent_no_such_name_errors++; 
        break;
    case NX_SNMP_ERROR_GENERAL:
    case NX_SNMP_ERROR_RESOURCEUNAVAILABLE:
    case NX_SNMP_ERROR_COMMITFAILED:
    case NX_SNMP_ERROR_UNDOFAILED:
        agent_ptr -> nx_snmp_agent_general_errors++; 
        break;
    }

    /* Set the request type to get/response.  */
    *request_type_ptr =  (UCHAR) NX_SNMP_ANS1_GET_RESPONSE;

    /* Update the error string with the error code and the object index.  */
    _nx_snmp_utility_error_info_set(error_string_ptr, error_code, error_index, packet_ptr -> nx_packet_data_end);

#ifndef NX_SNMP_DISABLE_V3
    /* Is the security set to encryption? */
    temp = (ULONG)agent_ptr -> nx_snmp_agent_v3_message_security_options;
    if (temp & NX_SNMP_SECURITY_PRIVACY)
    {

        /* Encrypt the PDU and setup the response to have an encryption header.  This
           will also compute our privacy parameter. */ 
        _nx_snmp_agent_encrypt_pdu(agent_ptr, NX_NULL, NX_NULL, 
                                   NX_NULL, NX_NULL, 
                                   NX_NULL, NX_NULL, pdu_privacy_ptr); 
    }

    /* Is the security set to authentication? */
    if (temp & NX_SNMP_SECURITY_AUTHORIZE)
    {
    
        /* Compute our authentication parameter.  */
        status = _nx_snmp_agent_add_auth_parameter(agent_ptr, packet_ptr, pdu_auth_parm_ptr);
    }
#endif

    /* Increment the sent packet counter.  */
    agent_ptr -> nx_snmp_agent_packets_sent++;
    
    /* Increment the get responses sent counter.  */
    agent_ptr -> nx_snmp_agent_getresponse_sent++;

    /* Send the response packet back to the requesting SNMP manager.  */
    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), packet_ptr, 
                                                agent_ptr -> nx_snmp_agent_current_manager_ip,
                                                agent_ptr -> nx_snmp_agent_current_manager_port);

    /* Check for successful call.  */
    if (status)
    {

        /* Release the packet.  */
        nx_packet_release(packet_ptr);
    }

    /* Return to caller.  */
    return;
}

#ifndef NX_SNMP_DISABLE_V1
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_version_1_process                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function processes the SNMP v1 request from the manager.       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    packet_ptr                            Pointer to packet containing  */ 
/*                                            the SNMP request            */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_allocate                    Allocate response packet      */ 
/*    nx_packet_release                     Release the packet            */ 
/*    nx_udp_socket_send                    Send the UDP packet           */ 
/*    _nx_snmp_utility_community_get        Get the community name        */ 
/*    _nx_snmp_utility_community_set        Set the community name        */ 
/*    _nx_snmp_utility_error_info_get       Get the error information     */ 
/*    _nx_snmp_utility_error_info_set       Set the error information     */ 
/*    _nx_snmp_utility_object_data_get      Get the object data           */ 
/*    _nx_snmp_utility_object_data_set      Set the object data           */ 
/*    _nx_snmp_utility_object_id_get        Get the object ID             */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_request_id_get       Get the request ID            */ 
/*    _nx_snmp_utility_request_id_set       Set the request ID            */ 
/*    _nx_snmp_utility_request_type_get     Get the request type          */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_sequence_get         Get the ANS.1 sequence        */ 
/*    _nx_snmp_utility_sequence_set         Set the ANS.1 sequence        */ 
/*    _nx_snmp_utility_version_get          Get the SNMP version          */ 
/*    _nx_snmp_utility_version_set          Set the SNMP version          */ 
/*    _nx_snmp_version_error_response       Send SNMP Manager error       */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry           SNMP Agent thread             */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr)
{

UINT        sequence_length, version, request_type, request_length;
UINT        error_code, error_index;
UINT        variable_list_length, variable_length;
ULONG       request_id;
UINT        status, length, objects;
UCHAR       *buffer_ptr;
UCHAR       *variable_start_ptr = NX_NULL;
UCHAR       *error_ptr, *request_type_ptr;
UINT        response_length;
UINT        total_variable_length = 0;
NX_PACKET   *response_packet_ptr;
UCHAR       *response_buffer_ptr;
UINT        response_sequence_length, response_type_length;
UINT        response_variable_list_length, response_variable_length;
UCHAR       *response_sequence_ptr, *response_type_ptr;
UCHAR       *response_variable_list_ptr, *response_variable_ptr;
UINT        packet_type;
INT         buffer_length;


    buffer_length = (INT)(packet_ptr -> nx_packet_length);

    /* Setup a pointer to the buffer.  */
    buffer_ptr =  packet_ptr -> nx_packet_prepend_ptr;

    /* Pickup the SEQUENCE field.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP VERSION field.  */
    length =  _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP Community String field.  */
    length =  _nx_snmp_utility_community_get(buffer_ptr,
                                             agent_ptr -> nx_snmp_agent_current_community_string,
                                             buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Save the request type pointer.  */
    request_type_ptr =  buffer_ptr;

    /* Pickup the SNMP Request type.  */
    length =  _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    agent_ptr -> nx_snmp_agent_request_get_type =  NX_FALSE;
    if ((request_type == NX_SNMP_GET_REQUEST) || 
        (request_type == NX_SNMP_GET_NEXT_REQUEST) ||
        (request_type == NX_SNMP_GET_BULK_REQUEST))
    {
         agent_ptr -> nx_snmp_agent_request_get_type =  NX_TRUE;
    }

    /* Pickup the SNMP Request ID.  */
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Save a pointer to the error string.  */
    error_ptr =  buffer_ptr;


    /* Pickup the SNMP Error information.  */
    length =  _nx_snmp_utility_error_info_get(buffer_ptr, &error_code, &error_index, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Determine if the received packet size is too big.  */
    if (packet_ptr -> nx_packet_next)
    {

        /* Call the error handling response routine.  */
        _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0);

        /* Done, return to caller.  */
        return;
    }

    if (agent_ptr -> nx_snmp_agent_username_process)
    {

        status = agent_ptr -> nx_snmp_agent_username_process(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string);

        /* Determine if the callback routine generated an error.  */
        if (status != NX_SUCCESS)
        {

            /* Increment the number of community/username errors.  */
            agent_ptr -> nx_snmp_agent_username_errors++;

#ifdef NX_SNMP_V1_AUTHORIZATION_ERROR_RESPONSE
            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, 0);
#else
            /* Authorization error response is not supported by version 1. */
            /* Release the packet.  */
            nx_packet_release(packet_ptr);
#endif

            /* Done, return to caller.  */
            return;
        }
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP Variable list length.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* At this point we have parsed the incoming SNMP request up to the first 
       variable.  */

    /* Now prepare response message so we can process the variables one by one.  */

    packet_type = NX_UDP_PACKET;

    /* Allocate the packet for the SNMP response.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a response packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the response packet.  */
    response_sequence_length =       0; 
    response_type_length =           0;
    response_variable_list_length =  0;

    /* Setup a pointer to the response packet's buffer area.  */
    response_buffer_ptr =  response_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the response sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the response.  */
    response_sequence_ptr =  response_buffer_ptr;

    /* First, write the sequence in the response packet.  A zero is written for now.  This will be 
       updated later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Now set the SNMP version in the response.  */
    response_length =  _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_1, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Set the SNMP community in the response message.  */
    response_length =  _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Remember the request type pointer, since it will need to be updated later.  */
    response_type_ptr =  response_buffer_ptr;

    /* Now set the request type in the response message.  */
    response_length =  _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Now set the request ID in the response message.  */
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* Set the response error information.  Assume everything is okay at this point.  */
    response_length =  _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* Remember the start of the response's variable list field.  */
    response_variable_list_ptr =  response_buffer_ptr;

    /* Setup the variable list response.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* At this point the response buffer is setup to exactly the same position the 
       SNMP Manager's input buffer is - right before the first variable.  We can
       now walk through the variable list to process each request and place the
       result in the response buffer.  */
    objects =  0;
    do
    {

        /* Remember the start of the variable.  */
        variable_start_ptr =  buffer_ptr;

        /* Pickup the first SNMP Variable length.  */
        length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length);

        /* Calculate the total variable size.  */
        total_variable_length =  variable_length + length;

        /* Determine if this variable will fit in the remaining length of the 
           variable list.  */
        if ((length == 0) || (total_variable_length > variable_list_length))
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Send an SNMP version error response.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1);

            /* Return to caller.  */
            return;
        }

        /* Move the buffer pointer up.  */
        buffer_ptr =  buffer_ptr + length;

        /* Update the size of the remaining buffer. */
        buffer_length -= (INT)length;

        /* Now pickup the object ID.  */
        length =  _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length);

        /* Determine if the object retrieval was successful.  */ 
        if (length == 0) 
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Move the buffer pointer up.  */
        buffer_ptr =  buffer_ptr + length;

        /* Update the size of the remaining buffer. */
        buffer_length -= (INT)length;

        /* Default the value to NULL.  */
        agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type =  0;

        /* Determine if a value is present.  */
        if (length != variable_length)
        {

            /* Pickup the value associated with this variable.  */
            length =  _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length);

            /* Determine if the object value was successful.  */ 
            if (length == 0) 
            {

                /* Increment the invalid packet error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_packets++;

                /* Increment the internal error counter.  */
                agent_ptr -> nx_snmp_agent_internal_errors++;

                /* Send an SNMP version error response.  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1);

                /* Release the packet.  */
                nx_packet_release(packet_ptr);

                /* Release the response packet.  */
                nx_packet_release(response_packet_ptr);

                /* Return to caller.  */
                return;
            }
        }

        /* At this point, we are ready to call the appropriate application request handling routine.  
           It is responsible for extracting or placing information in the object data structure.  */
        if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                               &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GETNEXT routine.  */
            status =  (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                                   &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        {

            /* Increment the total number of set variables.  */
            agent_ptr -> nx_snmp_agent_total_set_variables++;

            /* Call the application's SET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                               &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Check for an error status from the agent's request processing callback routine.  */
        if (status)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Per RFC2576 4.3 */
            switch(status)
            {
            case NX_SNMP_SUCCESS:
            case NX_SNMP_ERROR_TOOBIG:
                /* Call the error handling response routine.  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects+1);
                break;
            case NX_SNMP_ERROR_BADVALUE:
            case NX_SNMP_ERROR_WRONGVALUE:
            case NX_SNMP_ERROR_WRONGENCODING:
            case NX_SNMP_ERROR_WRONGTYPE:
            case NX_SNMP_ERROR_WRONGLENGTH:
            case NX_SNMP_ERROR_INCONSISTENTVALUE:
                /* Call the error handling response routine.  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1);
                break;
            case NX_SNMP_ERROR_NOSUCHNAME:
            case NX_SNMP_ERROR_NOACCESS:
            case NX_SNMP_ERROR_NOTWRITABLE:
            case NX_SNMP_ERROR_NOCREATION:
            case NX_SNMP_ERROR_INCONSISTENTNAME:
            case NX_SNMP_ERROR_AUTHORIZATION:
                /* Call the error handling response routine.  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects+1);
                break;
            case NX_SNMP_ERROR_GENERAL:
            case NX_SNMP_ERROR_RESOURCEUNAVAILABLE:
            case NX_SNMP_ERROR_COMMITFAILED:
            case NX_SNMP_ERROR_UNDOFAILED:
                /* Call the error handling response routine.  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_GENERAL, objects+1);
                break;
            default:
                /* Release the packet.  */
                nx_packet_release(packet_ptr);
            }

            /* Done, return to caller.  */
            return;
        }

        /* Determine if the returning object is valid.  */
        if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.'))
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Now ensure the returning object type is supported in V1.  */
        if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID))
        {

            /* Release the packet. */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1);
            
            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Everything is okay, place the object and object data into the response buffer.  */

        /* Remember the start of the variable response sequence.  */
        response_variable_ptr =  response_buffer_ptr;

        /* Clear the response variable size.  */
        response_variable_length =  0;

        /* Determine if there is enough room in the destination for the variable sequence.  */
        if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1);

            /* Done, return to caller.  */
            return;
        }

        /* Setup the variable response sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Place the object into the response buffer.  */
        response_length =  _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Insert the object's data into the response buffer.  */
        response_length =  _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Now update the response variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end);

        /* Adjust the pointer to the next variable.  */
        buffer_ptr =  variable_start_ptr + total_variable_length;

        /* Decrement the size of the variable list.  */
        variable_list_length =  variable_list_length - total_variable_length;

        /* Increment the object counter.  */
        objects++;

    } while (variable_list_length);

    /* At this point, several response fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end);

    /* Now the response packet's pointers must be setup so it can be sent.  */
    response_packet_ptr -> nx_packet_length =  (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr);
    response_packet_ptr -> nx_packet_append_ptr =  response_buffer_ptr;

    /* Release the original request packet.  */
    nx_packet_release(packet_ptr);

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_total_bytes_received +=  packet_ptr -> nx_packet_length;
    agent_ptr -> nx_snmp_agent_total_bytes_sent +=      response_packet_ptr -> nx_packet_length;
    if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        agent_ptr -> nx_snmp_agent_get_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        agent_ptr -> nx_snmp_agent_getnext_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST)
        agent_ptr -> nx_snmp_agent_getbulk_requests++;
    else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        agent_ptr -> nx_snmp_agent_set_requests++;

    /* Increment the sent packet counter.  */
    agent_ptr -> nx_snmp_agent_packets_sent++;
    
    /* Increment the get responses sent counter.  */
    agent_ptr -> nx_snmp_agent_getresponse_sent++;

    /* Send the response packet back to the requesting SNMP manager.  */
    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, 
                                                agent_ptr -> nx_snmp_agent_current_manager_ip,
                                                agent_ptr -> nx_snmp_agent_current_manager_port);

    /* Check for successful call.  */
    if (status)
    {

        /* Release the packet.  */
        nx_packet_release(response_packet_ptr);
    }
}
#endif  /* NX_SNMP_DISABLE_V1 */


#ifndef NX_SNMP_DISABLE_V2
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_version_2_process                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function processes the SNMP v2 request from the manager.       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    packet_ptr                            Pointer to packet containing  */ 
/*                                            the SNMP request            */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_allocate                    Allocate response packet      */ 
/*    nx_packet_release                     Release the packet            */ 
/*    nx_udp_socket_send                    Send the UDP packet           */ 
/*    _nx_snmp_utility_community_get        Get the community name        */ 
/*    _nx_snmp_utility_community_set        Set the community name        */ 
/*    _nx_snmp_utility_error_info_get       Get the error information     */ 
/*    _nx_snmp_utility_error_info_set       Set the error information     */ 
/*    _nx_snmp_utility_object_data_get      Get the object data           */ 
/*    _nx_snmp_utility_object_data_set      Set the object data           */ 
/*    _nx_snmp_utility_object_id_get        Get the object ID             */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_request_id_get       Get the request ID            */ 
/*    _nx_snmp_utility_request_id_set       Set the request ID            */ 
/*    _nx_snmp_utility_request_type_get     Get the request type          */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_sequence_get         Get the ANS.1 sequence        */ 
/*    _nx_snmp_utility_sequence_set         Set the ANS.1 sequence        */ 
/*    _nx_snmp_utility_version_get          Get the SNMP version          */ 
/*    _nx_snmp_utility_version_set          Set the SNMP version          */ 
/*    _nx_snmp_version_error_response       Send SNMP Manager error       */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry           SNMP Agent thread             */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_version_2_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr)
{

UINT        sequence_length, version, request_type, request_length;
UINT        non_repeaters, max_repetitions, current_repetitions, next_object;
UINT        variable_list_length, variable_length;
ULONG       request_id;
UINT        status, length, objects;
UCHAR       *buffer_ptr;
UCHAR       *variable_start_ptr = NX_NULL;
UCHAR       *error_ptr, *request_type_ptr;
UINT        response_length;
UINT        total_variable_length = 0;
NX_PACKET   *response_packet_ptr;
UCHAR       *response_buffer_ptr;
UINT        response_sequence_length, response_type_length;
UINT        response_variable_list_length, response_variable_length;
UCHAR       *response_sequence_ptr, *response_type_ptr;
UCHAR       *response_variable_list_ptr, *response_variable_ptr;
UINT        packet_type;
INT         buffer_length;

    buffer_length = (INT)(packet_ptr -> nx_packet_length);

    /* Setup a pointer to the buffer.  */
    buffer_ptr =  packet_ptr -> nx_packet_prepend_ptr;

    /* Pickup the SEQUENCE field.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP VERSION field.  */
    length =  _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP Community String field.  */
    length =  _nx_snmp_utility_community_get(buffer_ptr,
                                             agent_ptr -> nx_snmp_agent_current_community_string,
                                             buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Save the request type pointer.  */
    request_type_ptr =  buffer_ptr;

    /* Pick up the SNMP Request type.  */
    length =  _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    agent_ptr -> nx_snmp_agent_request_get_type =  NX_FALSE;
    if ((request_type == NX_SNMP_GET_REQUEST) || 
        (request_type == NX_SNMP_GET_NEXT_REQUEST) ||
        (request_type == NX_SNMP_GET_BULK_REQUEST))
    {
         agent_ptr -> nx_snmp_agent_request_get_type =  NX_TRUE;
    }

    /* Pickup the SNMP Request ID.  */
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Save a pointer to the error string.  */
    error_ptr =  buffer_ptr;

    /* Pickup the SNMP Error information.  This is actually used to derive the GETBULK
       information in SNMP V2 and above.  */
    length =  _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }


    /* Determine if the received packet size is too big.  */
    if (packet_ptr -> nx_packet_next)
    {

        /* Call the error handling response routine.  */
        _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0);

        /* Done, return to caller.  */
        return;
    }



    /* Check to see if there is a username processing routine.  */
    if (agent_ptr -> nx_snmp_agent_username_process)
    {

        /* Yes, there is a callback routine to process the community/username.  */
        status =  (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string);

        /* Determine if the callback routine generated an error.  */
        if (status != NX_SUCCESS)
        {

            /* Increment the number of community/username errors.  */
            agent_ptr -> nx_snmp_agent_username_errors++;

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_AUTHORIZATION, 0);

            /* Done, return to caller.  */
            return;
        }
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP Variable list length.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* At this point we have parsed the incoming SNMP request up to the first 
       variable.  */

    /* Now prepare response message so we can process the variables one by one.  */


    packet_type = NX_UDP_PACKET;

    /* Allocate the packet for the SNMP response.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a response packet was allocated.  */
    if (status)
    {

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the response packet.  */
    response_sequence_length =       0; 
    response_type_length =           0;
    response_variable_list_length =  0;

    /* Setup a pointer to the response packet's buffer area.  */
    response_buffer_ptr =  response_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the response sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the response.  */
    response_sequence_ptr =  response_buffer_ptr;

    /* First, write the sequence in the response packet.  A zero is written for now.  This will be 
       updated later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Now set the SNMP version in the response.  */
    response_length =  _nx_snmp_utility_version_set(response_buffer_ptr, version, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Set the SNMP community in the response message.  */
    response_length =  _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Remember the request type pointer, since it will need to be updated later.  */
    response_type_ptr =  response_buffer_ptr;

    /* Now set the request type in the response message.  */
    response_length =  _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Now set the request ID in the response message.  */
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* Set the response error information.  Assume everything is okay at this point.  */
    response_length =  _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* Remember the start of the response's variable list field.  */
    response_variable_list_ptr =  response_buffer_ptr;

    /* Setup the variable list response.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* At this point the response buffer is setup to exactly the same position the 
       SNMP Manager's input buffer is - right before the first variable.  We can
       now walk through the variable list to process each request and place the
       result in the response buffer.  */
    objects =              0;
    next_object =          NX_TRUE;
    current_repetitions =  max_repetitions;
    do
    {

        /* Determine if the next object should be retrieved.  */
        if (next_object)
        {

            /* Remember the start of the variable.  */
            variable_start_ptr =  buffer_ptr;

            /* Pickup the first SNMP Variable length.  */
            length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length);

            /* Calculate the total variable size.  */
            total_variable_length =  variable_length + length;

            /* Determine if this variable will fit in the remaining length of the 
               variable list.  */
            if ((length == 0) || (total_variable_length > variable_list_length))
            {

                /* Increment the invalid packet error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_packets++;

                /* Release the response packet.  */
                nx_packet_release(response_packet_ptr);

                /* Call the error handling response routine. This will release the packet  */
                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1);

                /* Return to caller.  */
                return;
            }

            /* Move the buffer pointer up.  */
            buffer_ptr =  buffer_ptr + length;

            /* The buffer pointer is moved by the length. Update buffer size */
            buffer_length -= (INT)length;

            /* Now pickup the object ID.  */
            length =  _nx_snmp_utility_object_id_get(buffer_ptr,
                                                     agent_ptr -> nx_snmp_agent_current_octet_string,
                                                     buffer_length);

            /* Determine if the object retrieval was successful.  */ 
            if (length == 0) 
            {

                /* Increment the invalid packet error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_packets++;

                /* Increment the internal error counter.  */
                agent_ptr -> nx_snmp_agent_internal_errors++;

                /* Release the packet.  */
                nx_packet_release(packet_ptr);

                /* Release the response packet.  */
                nx_packet_release(response_packet_ptr);

                /* Return to caller.  */
                return;
            }

            /* Move the buffer pointer up.  */
            buffer_ptr =  buffer_ptr + length;

            /* The buffer pointer is moved by the length. Update buffer size */
            buffer_length -= (INT)length;

            /* Default the value to NULL.  */
            agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type =  0;

            /* Determine if a value is present.  */
            if (length != variable_length)
            {

                /* Pickup the value associated with this variable.  */
                length =  _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length);

                /* Determine if the object value was successful.  */ 
                if (length == 0) 
                {

                    /* Increment the invalid packet error counter.  */
                    agent_ptr -> nx_snmp_agent_invalid_packets++;

                    /* Increment the internal error counter.  */
                    agent_ptr -> nx_snmp_agent_internal_errors++;

                    /* Send an SNMP version error response.  */
                    _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1);

                    /* Release the packet.  */
                    nx_packet_release(packet_ptr);

                    /* Release the response packet.  */
                    nx_packet_release(response_packet_ptr);

                    /* Return to caller.  */
                    return;
                }
            }
        }

        /* At this point, we are ready to call the appropriate application request handling routine.  
           It is responsible for extracting or placing information in the object data structure.  */
        if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GETNEXT routine.  */
            status =  (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST)
        {
        
            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Clear the next object flag.  */
            next_object =  NX_FALSE;

            /* Call the application's GETNEXT routine.  */
            status =  (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data));

            /* Decrement the number of non-repeaters.  */
            if (non_repeaters)
            {

                /* Decrement the number of non-repeaters.  */
                non_repeaters--;

                /* Set the next object flag to move to the next entry of the request.  */
                next_object =  NX_TRUE;
            }
            else 
            {

                /* Decrement the repetitions.  */
                if (current_repetitions)
                    current_repetitions--;

                /* Determine if there are more repetitions or if the end of MIB was detected.  */
                if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW))
                {

                    /* Reset the current repetition.  */
                    current_repetitions =  max_repetitions;

                    /* Set the next object flag to true.  */
                    next_object =  NX_TRUE;
                }
            }
        }
        else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        {

            /* Increment the total number of set variables.  */
            agent_ptr -> nx_snmp_agent_total_set_variables++;

            /* Call the application's SET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Check for an error status from the agent's request processing callback routine.  */
        if (status)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Determine if the returning object is valid.  */
        if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.'))
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Now ensure the returning object type is valid.  */
        if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW))
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Everything is okay, place the object and object data into the response buffer.  */

        /* Remember the start of the variable response sequence.  */
        response_variable_ptr =  response_buffer_ptr;

        /* Clear the response variable size.  */
        response_variable_length =  0;

        /* Determine if there is enough room in the destination for the variable sequence.  */
        if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Setup the variable response sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Place the object into the response buffer.  */
        response_length =  _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Insert the object's data into the response buffer.  */
        response_length =  _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Now update the response variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end);

        /* Only update the source object information if the next object flag is set.  */
        if (next_object)
        {

            /* Adjust the pointer to the next variable.  */
            buffer_ptr =  variable_start_ptr + total_variable_length;

            /* Decrement the size of the variable list.  */
            variable_list_length =  variable_list_length - total_variable_length;

            /* Increment the object counter.  */
            objects++;
        }

    } while ((variable_list_length) || (next_object == NX_FALSE));

    /* At this point, several response fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end);

    /* Now the response packet's pointers must be setup so it can be sent.  */
    response_packet_ptr -> nx_packet_length =  (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr);
    response_packet_ptr -> nx_packet_append_ptr =  response_buffer_ptr;

    /* Release the original request packet.  */
    nx_packet_release(packet_ptr);

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_total_bytes_received +=  packet_ptr -> nx_packet_length;
    agent_ptr -> nx_snmp_agent_total_bytes_sent +=      response_packet_ptr -> nx_packet_length;
    if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        agent_ptr -> nx_snmp_agent_get_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        agent_ptr -> nx_snmp_agent_getnext_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST)
        agent_ptr -> nx_snmp_agent_getbulk_requests++;
    else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        agent_ptr -> nx_snmp_agent_set_requests++;

    /* Increment the sent packet counter.  */
    agent_ptr -> nx_snmp_agent_packets_sent++;
    
    /* Increment the get responses sent counter.  */
    agent_ptr -> nx_snmp_agent_getresponse_sent++;

    /* Send the response packet back to the requesting SNMP manager.  */
    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, 
                                                agent_ptr -> nx_snmp_agent_current_manager_ip,
                                                agent_ptr -> nx_snmp_agent_current_manager_port);

    /* Check for successful call.  */
    if (status)
    {

        /* Release the packet.  */
        nx_packet_release(response_packet_ptr);
    }
}
#endif


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function processes the SNMP v3 request from the manager.       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */ 
/*    packet_ptr                            Pointer to packet containing  */ 
/*                                            the SNMP request            */ 
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_des_encrypt                       Encrypt bytes                 */ 
/*    _nx_des_decrypt                       Decrypt bytes                 */ 
/*    _nx_des_key_set                       Set the DES key               */ 
/*    _nx_md5_digest_calculate              Finalize MD5 calculation      */ 
/*    _nx_md5_initialize                    Initialize MD5 calculation    */ 
/*    _nx_md5_update                        Update MD5 calculation        */ 
/*    nx_packet_allocate                    Allocate response packet      */ 
/*    nx_packet_release                     Release the packet            */ 
/*    nx_udp_socket_send                    Send the UDP packet           */ 
/*    _nx_snmp_utility_error_info_get       Get the error information     */ 
/*    _nx_snmp_utility_error_info_set       Set the error information     */ 
/*    _nx_snmp_utility_object_data_get      Get the object data           */ 
/*    _nx_snmp_utility_object_data_set      Set the object data           */ 
/*    _nx_snmp_utility_object_id_get        Get the object ID             */ 
/*    _nx_snmp_utility_object_id_set        Set the object ID             */ 
/*    _nx_snmp_utility_octet_get            Get octet string              */ 
/*    _nx_snmp_utility_octet_set            Set octet string              */ 
/*    _nx_snmp_utility_request_id_get       Get the request ID            */ 
/*    _nx_snmp_utility_request_id_set       Set the request ID            */ 
/*    _nx_snmp_utility_request_type_get     Get the request type          */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_sequence_get         Get the ANS.1 sequence        */ 
/*    _nx_snmp_utility_sequence_set         Set the ANS.1 sequence        */ 
/*    _nx_snmp_utility_version_get          Get the SNMP version          */ 
/*    _nx_snmp_utility_version_set          Set the SNMP version          */ 
/*    _nx_snmp_version_error_response       Send SNMP Manager error       */ 
/*    _nx_snmp_version_3_discovery_respond  Send discovery response       */ 
/*    _nx_sha1_digest_calculate             Finalize SHA calculation      */ 
/*    _nx_sha1_initialize                   Initialize SHA calculation    */ 
/*    _nx_sha1_update                       Update SHA calculation        */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_agent_thread_entry           SNMP Agent thread             */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_version_3_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr)
{

UINT        i, sequence_length, version, request_type, request_length;
UINT        header_sequence_length, security_sequence_length, pdu_sequence_length;
UINT        non_repeaters, max_repetitions, current_repetitions, next_object;
UINT        variable_list_length, variable_length;
ULONG       request_id;
UINT        status, length, objects;
UCHAR       *buffer_ptr;
UCHAR       *variable_start_ptr = NX_NULL;
UCHAR       *error_ptr, *request_type_ptr, *temp_ptr;
UINT        response_length;
UINT        total_variable_length = 0;
NX_PACKET   *response_packet_ptr;
UINT        context_engine_size, context_name_size;
UCHAR       *response_buffer_ptr;
UINT        response_sequence_length, response_header_length, response_security_length, response_pdu_length, response_type_length;
UINT        response_variable_list_length, response_variable_length;
UCHAR       *response_sequence_ptr, *response_header_ptr, *response_security_ptr, *response_pdu_ptr, *response_type_ptr;
UCHAR       *response_variable_list_ptr, *response_variable_ptr;
UCHAR       temp_string[NX_SNMP_DIGEST_SIZE];
UINT        packet_type;
UCHAR       *response_encryption_size_ptr = NX_NULL;
UCHAR       *response_authentication_ptr = NX_NULL, *response_privacy_ptr = NX_NULL;
UCHAR       *request_authentication_ptr = NX_NULL; 
UCHAR       key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR       key2[NX_SNMP_DIGEST_WORKING_SIZE];
UINT        authenticate_message = NX_FALSE; 
UINT        encrypt_message = NX_FALSE; 
UCHAR       message_sec_level;
UINT        mask;
INT         buffer_length;

                           
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("\nReceived a SNMPv3 request\n\r");
#endif

    buffer_length = (INT)(packet_ptr -> nx_packet_length);

    /* Setup a pointer to the buffer.  */
    buffer_ptr =  packet_ptr -> nx_packet_prepend_ptr;

    /* Pickup the SEQUENCE field.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Pickup the SNMP VERSION field.  */
    length =  _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /***** Now we are positioned in front of the global header.  *****/

    /* Pickup the sequence for the header data, which includes the message ID, maximum reply size,
       flags, and the security model.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &header_sequence_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Position to the next field.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /********************************************************/
    /*                      Get the message ID              */
    /********************************************************/
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_id), buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Position to the next field.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /********************************************************/
    /*                      Get the message size            */
    /********************************************************/
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_size), buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Position to the next field.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /********************************************************/
    /*                Get the security options              */
    /********************************************************/
    length =  _nx_snmp_utility_octet_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_options),
                                         sizeof(agent_ptr -> nx_snmp_agent_v3_message_security_options), &status, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Extracted security options: 0x%x\n\r", agent_ptr -> nx_snmp_agent_v3_message_security_options);
#endif

    /* Position to the next field.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    mask = NX_SNMP_SECURITY_AUTHORIZE | NX_SNMP_SECURITY_PRIVACY ;

    /* We want to mask out the reportable bit. */
    agent_ptr -> nx_snmp_agent_v3_message_security_options = (UCHAR)(agent_ptr -> nx_snmp_agent_v3_message_security_options & mask);

    /********************************************************/
    /*                Get the security type                 */
    /********************************************************/
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_type), buffer_length);

    /* Check for a valid packet.  */
    if ((length == 0) || (agent_ptr -> nx_snmp_agent_v3_message_security_type != NX_SNMP_USM_SECURITY_MODEL))
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Position to the next field.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /**** Now we are positioned in front of the security parameters field.  ****/

    /* Determine if there are security parameters.  */
    if ((buffer_ptr[0] == NX_SNMP_ANS1_OCTET_STRING) && (buffer_ptr[1]))
    {

        /* Position the buffer pointer past the octet string.  */
        buffer_ptr =  buffer_ptr + 2;

        /* Pickup the sequence for the security data.  */
        length =  _nx_snmp_utility_sequence_get(buffer_ptr, &security_sequence_length, buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /********************************************************/
        /*         Get the authoritative engine ID              */
        /********************************************************/
        length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_context_engine,
                                             sizeof(agent_ptr -> nx_snmp_agent_v3_security_context_engine),
                                             &(agent_ptr -> nx_snmp_agent_v3_security_context_engine_size), buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /********************************************************/
        /*         Get the number of engine reboots             */
        /********************************************************/
        length =  _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boots), buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /********************************************************/
        /*         Get the engine boot time                     */
        /********************************************************/
        length =  _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time), buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /********************************************************/
        /*         Get the security username                    */
        /********************************************************/
        length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name,
                                             sizeof(agent_ptr -> nx_snmp_agent_v3_security_user_name), &(agent_ptr -> nx_snmp_agent_v3_security_user_name_size), buffer_length);
            
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Security name parsed: %s Size: %d\n\r", &agent_ptr -> nx_snmp_agent_v3_security_user_name[0], agent_ptr -> nx_snmp_agent_v3_security_user_name_size);

#endif
        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Null terminate the User Name.  */
        agent_ptr -> nx_snmp_agent_v3_security_user_name[agent_ptr -> nx_snmp_agent_v3_security_user_name_size] =  0;

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        /********************************************************/
        /*         Get the security authentication parameter    */
        /********************************************************/
        length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_authentication,
                                             sizeof(agent_ptr -> nx_snmp_agent_v3_security_authentication), &(agent_ptr -> nx_snmp_agent_v3_security_authentication_size), buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }
#ifndef NX_SNMP_NO_SECURITY
        /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter.  */

        request_authentication_ptr =  buffer_ptr + 2;
#endif

        /* Position to the next field.  */
        buffer_ptr =  buffer_ptr + length;

        /* The buffer pointer is moved by the length. Update buffer size */
        buffer_length -= (INT)length;

        pdu_privacy_ptr = buffer_ptr + 2; 

        /********************************************************/
        /*         Get the security privacy parameter           */
        /********************************************************/

        /* This is effectively the salt which will be used to unencrypt the PDU. */
        length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_privacy,
                                             sizeof(agent_ptr -> nx_snmp_agent_v3_security_privacy), &(agent_ptr -> nx_snmp_agent_v3_security_privacy_size), buffer_length);

        /* Check for a valid packet.  */
        if (length == 0)
        {

            /* Increment the invalid packet error counter.  */
            agent_ptr -> nx_snmp_agent_invalid_packets++;

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }
    }
    else
    {

        /* Position past the empty security parameter field.  */
        length =  2;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* Save the location where the request type is located (after context engine ID and name). */
    temp_ptr = buffer_ptr;

    /********************************************************/
    /*         Determine if we send a report vs response    */
    /********************************************************/

    /* Check if Engine ID is missing AND the security user name is blank. */
    if ((agent_ptr -> nx_snmp_agent_v3_security_context_engine_size == 0) &&
         (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0))
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("No Engine ID, no user name, this is a discovery request. \n\r");
#endif
        agent_ptr -> nx_snmp_agent_unknown_engineid_count++;

        _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length);

        /* We're done ! Release the received SNMP packet.  */
        nx_packet_release(packet_ptr);

        return;
    }
    /* Check for a mismatched Engine ID. */
    else if ((memcmp(&agent_ptr -> nx_snmp_agent_v3_context_engine[0], 
                     &agent_ptr -> nx_snmp_agent_v3_security_context_engine[0], 
                     agent_ptr -> nx_snmp_agent_v3_security_context_engine_size) != 0))
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Detect a mismatched (non null) engine ID\n\r");
#endif
         /*  Increment the invalid packet error counter.  */
         agent_ptr -> nx_snmp_agent_unknown_engineid_count++;

         _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length);

         /* Release the packet.  */
         nx_packet_release(packet_ptr);

         /*  We will wait for the browser to make a discovery request (blank engine ID). */
        return;
    }
    /* Check for missing username in the securities header. */
    else if (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0)        
    {
        
        /* Missing user name in the securities field. */

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Request is missing a securities username\n\r");
#endif

        /* Update the unknown or missing user name at least. */
        agent_ptr -> nx_snmp_agent_unknown_username_count++;

        _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length);

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        return;
    }
    /* Check for valid username in the security parameters. */
    else if (agent_ptr -> nx_snmp_agent_username_process)
    {

        status =  (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name);
     
        if (status != NX_SUCCESS)
        {
            /* Unknown user name in the securities field. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Error in username callback: 0x%x\n\r", status);
#endif

            agent_ptr -> nx_snmp_agent_unknown_username_count++;
            
            _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length);

            /* Release the packet.  */
            nx_packet_release(packet_ptr);
            
            return;
        }

         /* Engine ID and username appear acceptable, Not a disco request. Check the boot time. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
         NX_SNMPV3_DBG_PRINTF("Request has a valid Engine ID and user name. Check the boot and boot time\n\r");
#endif

        /* Check if both sides have authentication enabled.    */
        if (((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) &&
            (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL)) 
        {
            /* They do. So now we must check for mismatched boot data. */
            if (agent_ptr -> nx_snmp_agent_v3_context_engine_boots != agent_ptr -> nx_snmp_agent_v3_security_engine_boots)
            {

                 /* Boot count does not match.  */
                agent_ptr -> nx_snmp_agent_mismatched_time_count++;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
                 NX_SNMPV3_DBG_PRINTF("Detect a %d'th mismatch in the boot count. Agent boot count: %d; Browser boot count %d\n\r", 
                                      agent_ptr -> nx_snmp_agent_mismatched_time_count,
                                      agent_ptr -> nx_snmp_agent_v3_context_engine_boots,
                                      agent_ptr -> nx_snmp_agent_v3_security_engine_boots);
#endif    
    
                 _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length);

                 /* Release the packet.  */
                 nx_packet_release(packet_ptr);
    
                 /* Return to caller.  */
                 return;
            }
            /* Determine if the browser boot time exceeds ours by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */
            else if  ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) &&
                      ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) > NX_SNMP_TIME_WINDOW))
            {

                 agent_ptr -> nx_snmp_agent_mismatched_time_count++;

                 /* Outside acceptable limits. Do not reply to this request. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
                 NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is less than Browser boot time %d\n\r", 
                                      agent_ptr -> nx_snmp_agent_mismatched_time_count,
                                      agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, 
                                      agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time);
#endif    
    
                 _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length);

                 /* Release the packet.  */
                 nx_packet_release(packet_ptr);
    
                 /* Return to caller.  */
                 return;
            }
            /* Determine if the our boot time exceeds the browser boot time by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */
            else if  ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) &&
                      ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) > NX_SNMP_TIME_WINDOW))
            {

                agent_ptr -> nx_snmp_agent_mismatched_time_count++;

                 /* Outside acceptable limits. Do not reply to this request. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
                NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is greater than Browser boot time %d\n\r", 
                                     agent_ptr -> nx_snmp_agent_mismatched_time_count,
                                     agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, 
                                     agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time);
#endif    
    
                _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length);

                 /* Release the packet.  */
                 nx_packet_release(packet_ptr);
    
                 /* Return to caller.  */
                 return;
            }
        }
    }


    authenticate_message = NX_FALSE;

    /* Check again if the incoming request specifies authentication. */
    if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1)  
    {

        /* Check if our key is not set up or authentication is not enabled (in which
           case the authentication key is NULL anyway). */
        if (agent_ptr -> nx_snmp_agent_v3_authentication_key == NX_NULL)
        {

            /* The request has an unsupported (as in none) authentication level requested. This is an error. */

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__);
#endif
            agent_ptr -> nx_snmp_agent_unsupported_sec_count++;

            _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length);

            /* We're done ! Release the received SNMP packet.  */
            nx_packet_release(packet_ptr);

            return;
        }
        else
        {
            /* Otherwise Ok to process authentication parameter. */
            authenticate_message = NX_TRUE;
        }
    }
    /* Check if the incoming message is not requesting authentication. */
    else  
    {
    
       if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL)
       {

           /* The request has an unsupported (as in none) authentication level requested. This
              is an error. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__);
#endif
            agent_ptr -> nx_snmp_agent_unsupported_sec_count++;

            _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length);

            /* We're done ! Release the received SNMP packet.  */
            nx_packet_release(packet_ptr);

            return;
       }
    }

    /********************************************************/
    /*               Check Authentication Parameter         */
    /********************************************************/

    /* Are we processing the authentication parameter? */
    if (authenticate_message == NX_TRUE)
    {

        /* Yes, authentication is required.  */

        /* Mark the location in the request buffer. */
        pdu_auth_parm_ptr = request_authentication_ptr;

        /* Clear the authentication field in the message.  To calculate the 
           digest this must be cleared.  Also position past the string and length.  */
        for (i = 0; i < agent_ptr -> nx_snmp_agent_v3_security_authentication_size; i++)
        {

            /* Clear the byte.  */
            *request_authentication_ptr++ =  0;
        }
        /* Now determine which authentication is required.  */
        if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY)
        {

            /* Copy the base MD5 key into key1.  */
            for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base MD5 key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Calculate prepend Key1.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Prepend Key2 to the result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2);
        }
        else if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY)
        {

            /* Copy the base SHA key into key1.  */
            for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base SHA key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Calculate prepend Key1.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1);

             /* Prepare to calculate the final MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Prepend Key2 to the result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2);
        }
        else
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Authentication error. Drop the request. Line %d \n\r", __LINE__);
#endif
            /* Increment the authentication error counter.  */
            agent_ptr -> nx_snmp_agent_authentication_errors++;

            /* Release the original packet.  */
            nx_packet_release(packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* At this point, key2 contains the computed digest of the message.  If this doesn't match,
           then the message is invalid.  */
        for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
        {

            /* Check for a mismatch.  */
            if (key2[i] != agent_ptr -> nx_snmp_agent_v3_security_authentication[i])
            {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
                NX_SNMPV3_DBG_PRINTF("Authentication mismatch. Drop the request. Line %d \n\r", __LINE__);
#endif
                /* We are not. Increment the authentication error counter.  */
                agent_ptr -> nx_snmp_agent_authentication_errors++;

                /* Release the original packet.  */
                nx_packet_release(packet_ptr);

                /* Return to caller.  */
                return;
            }
        }
    }

    /* Now prepare response message so we can process the variables one by one.  */

    packet_type = NX_UDP_PACKET;

    /* Allocate the packet for the SNMP response.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a response packet was allocated.  */
    if (status)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Response packet allocate error. Status: 0x%x\n\r", status);
#endif

        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the response packet.  */
    response_sequence_length =       0; 
    response_header_length =         0;
    response_security_length =       0;
    response_pdu_length =            0;
    response_type_length =           0;
    response_variable_list_length =  0;

    /* Setup a pointer to the response packet's buffer area.  */
    response_buffer_ptr =  response_packet_ptr -> nx_packet_prepend_ptr;

    /* This is also the response sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the response.  */
    response_sequence_ptr =  response_buffer_ptr;

    /* First, write the sequence in the response packet.  A zero is written for now.  This will be 
       updated later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /********************************************************/
    /*               Set the Version ID                     */
    /********************************************************/
    response_length =  _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_3, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet.  */
        nx_packet_release(response_packet_ptr);

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Save the pointer to the global header.  */
    response_header_ptr =  response_buffer_ptr;

    /* Write the sequence for the global header in the response packet.  A zero is written for now.  
       This will be updated later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /********************************************************/
    /*               Set the request ID                     */
    /********************************************************/
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the header sequence length.  */
    response_header_length =  response_header_length + response_length;

    /********************************************************/
    /*        Set the maximum message size                  */
    /********************************************************/
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the header sequence length.  */
    response_header_length =  response_header_length + response_length;

    /********************************************************/
    /*        Set the message security options              */
    /********************************************************/
    message_sec_level = agent_ptr -> nx_snmp_agent_v3_message_security_options;

    response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, (UCHAR *)&message_sec_level, 1, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the header sequence length.  */
    response_header_length =  response_header_length + response_length;

    /****************************************************/
    /*             Set the security type                */
    /****************************************************/
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the header sequence length.  */
    response_header_length =  response_header_length + response_length;

    /* At this point, we have successfully built the security header.  Now, we need to build 
       the security parameters field.  */

    /* First setup the octet string field.  */
    response_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
    response_buffer_ptr[1] =  0;

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + 2;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + 2;

    /* Remember the security header length pointer.  */
    response_security_ptr =  response_buffer_ptr;

    /* Now set the sequence of the USM security parameters.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /****************************************************/
    /*             Set the Context Engine               */
    /****************************************************/
    response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    /****************************************************/
    /*                Set the Boot Count                */
    /****************************************************/
    if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0)
    {
        /* No security, no time synching, so set boot data to zero. */
        response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);
    }
    else
    {
        /* Set the actual boot count. */
        response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, response_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    /****************************************************/
    /*                Set the Boot Time                 */
    /****************************************************/

    if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0)
    {
        /* No security, no time synching, so set boot data to zero. */
        response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);
    }
    else
    {

        /* Get the tick count since last boot up. */
        agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);

        /* Set the actual boot count. */
        response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, response_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    /****************************************************/
    /*             Set the security user name           */
    /****************************************************/

    /* (Use the security name in the request message) */
    response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    /* Initialize the temporary string to zero. */
    for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
      temp_string[i] =  0;

    /****************************************************/
    /*      Set the security Authentication parameter   */
    /****************************************************/

    /* Now setup the authentication parameter if authentication is enabled, and only if called for.   */
    if (authenticate_message == NX_TRUE)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Authenticating: initialize auth parameter to zero in response packet. (Line %d) \n\r", __LINE__);
#endif

        /* All set to add an authentication parameter. For now, set to all zeroes. */
        response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, response_packet_ptr -> nx_packet_data_end);

        /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter.  */
        response_authentication_ptr =  response_buffer_ptr + 2; 
    }
    else
    {
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Not Authenticating: set auth parameter to null in response packet. (Line %d) \n\r", __LINE__);
#endif
        /* No security enabled so set this as an empty parameter. */
        response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end);

    }

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    encrypt_message = NX_FALSE;

    /* Check if the incoming request specifies authentication. A discovery request should not have
       the authentication (or encxryption) flags set. */
    if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY) >= 2)  
    {

        /* Check if our key is not set up or privacy is not enabled (in which
           case the privacy key is NULL anyway). */
        if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL)
        {

            /* The request has an unsupported (as in none) privacy level requested. This is an error. */

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__);
#endif
            agent_ptr -> nx_snmp_agent_unsupported_sec_count++;

            _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            /* We're done ! Release the received SNMP packet.  */
            nx_packet_release(packet_ptr);

            return;
        }
        else
        {
            /* Otherwise Ok to process encrypt/decrypt SNMPv3 data. */
            encrypt_message = NX_TRUE;
        }
    }

    /* Check if the incoming message is not requesting privacy. */
    else  
    {
    
       if (agent_ptr -> nx_snmp_agent_v3_privacy_key != NX_NULL)
       {

           /* The request has an unsupported (as in none) privacy level requested. This
              is an error. */
#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__);
#endif
            agent_ptr -> nx_snmp_agent_unsupported_sec_count++;

            _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            /* We're done ! Release the received SNMP packet.  */
            nx_packet_release(packet_ptr);

            return;
       }
    }

    /****************************************************/
    /*      Set the security Privacy parameter          */
    /****************************************************/

    /* Are we applying encryption to our response? */
    if (encrypt_message == NX_FALSE)
    {
    
        /* No, so set the privacy field as an empty parameter. */
        response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end);
    }
    else
    {
    
        /* Initialize the 8 character privacy parameter (salt) to all zeros field initially.  */
        response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, 8, response_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the original packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    if (encrypt_message == NX_TRUE)
    {
    
        /* Remember the pointer to the actual 8 byte privacy parameter.  */
        response_privacy_ptr =  response_buffer_ptr + 2;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Adjust the security sequence length.  */
    response_security_length =  response_security_length + response_length;

    /****************************************************/
    /*         Decrypt the privacy data                 */
    /****************************************************/

    /* Check if encryption is required */
    if (encrypt_message == NX_TRUE)
    {

        response_encryption_size_ptr = 0x0;

        /* Save the location if we need to return an error message. */
        pdu_buffer_ptr = buffer_ptr;

        status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, response_buffer_ptr,  &response_encryption_size_ptr, &response_length, buffer_length);

        if (status != NX_SUCCESS)
        {

            /* Increment the privacy error counter.  */
            agent_ptr -> nx_snmp_agent_privacy_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            return;
        }

        /* This is typically coded as 0x30 0x29 [or whatever length] 0x04 0x82 or [length] without
           the multi byte coding. This will also handle 0x81 "multi byte" coding. */ 
        if (buffer_ptr[3] & NX_SNMP_ANS1_MULTI_BYTES)
        {

            /* Get the type of length of the string */
            UINT temp = (UINT)(buffer_ptr[3] & 0x7F);
    
            if (temp == 2)
            {

                pdu_length =  (UINT) (*(buffer_ptr+ 4) << 8) | ((UINT) *(buffer_ptr+5));
                pdu_buffer_ptr = buffer_ptr;
            }
        
            else if (temp == 1)
            {
                pdu_length = *(buffer_ptr + 4);
                pdu_buffer_ptr = buffer_ptr;
            }
            else
            {
            
                /* String is either null or too big, return a zero length to indicate an error.  */
                return;
            }
        }
        else  /* Assume one byte */
        {
            pdu_length = *(buffer_ptr + 3);
            pdu_buffer_ptr = buffer_ptr;
        }

        response_length = 4; 

    }

    /* Now we can process the request type pointer */
    while (temp_ptr < packet_ptr -> nx_packet_append_ptr)
    {
        temp_ptr++;

        /* Check for Get request type. */
        if ((*temp_ptr == NX_SNMP_ANS1_GET_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_GET_BULK_REQUEST)|| 
            (*temp_ptr == NX_SNMP_ANS1_GET_NEXT_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_SET_REQUEST))
        {
            break;
        }
    }

    /* Check for invalid packet. */
    if (temp_ptr == packet_ptr -> nx_packet_append_ptr)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }
    
    /* Save the request type pointer.  */
    request_type_ptr =  temp_ptr;

    /* Save the response pdu sequence pointer.  */
    response_pdu_ptr =  response_buffer_ptr;

    /* Move the response buffer pointer.  */
    response_buffer_ptr =  response_buffer_ptr + response_length; 

    /* Increment the number of response sequence bytes.  */
    response_sequence_length = response_sequence_length + response_length; 

    /****************************************************/
    /*        Get the PDU sequence length               */
    /****************************************************/
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &pdu_sequence_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /****************************************************/
    /*            Get the PDU engine ID                 */
    /****************************************************/
    length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string,
                                         sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_engine_size, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;


    /******************************************************************************/
    /*            SET the PDU Sequence Header if the response is encrypted.       */
    /******************************************************************************/

    /* If the message is encrypted we have to insert an PDU "inner" sequence header. Because 
       we will use the multibyte sequence 0x30 82 xx yy format, we have to update the enclosing
       sequences (total response length and pdu length and their respective pointers accordingly. 
    */
    if (encrypt_message)
    {

        /* Move the response buffer pointer.  */
        response_buffer_ptr =  response_buffer_ptr + 4; 

        /* Increment the number of response sequence bytes.  */
        response_sequence_length = response_sequence_length + 4; 

        /* Increment the response pdu sequence pointer.  */
        response_pdu_ptr =  response_pdu_ptr + 4;

         /* Increment the pdu length for this sequence header.  */
        response_pdu_length =  response_pdu_length + 4;

    }

    /****************************************************/
    /*            SET the PDU engine ID                 */
    /****************************************************/
    response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (response_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response pointer forward.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Increment the sequence length.  */
    response_sequence_length =       response_sequence_length + response_length; 

    /* Increment the pdu length.  */
    response_pdu_length =            response_pdu_length + response_length;

    /****************************************************/
    /*            Get the PDU engine name               */
    /****************************************************/
    length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string,
                                         sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_name_size, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

 
    /* The browser uses the context name from the SNMP Agent to confirm
       the response is coming from the SNMP Agent it sent the request to. They must match. 
       The request ID only matches the request with response.  A user may have multiple 
       requests. There may be circumstances where the SNMP Agent only responds with
       one context name. Don't know what that would be. */

    /* Check if the SNMP agent has set a PDU engine name yet. */
    if (agent_ptr -> nx_snmp_agent_v3_context_name_size == 0)
    {  

        /* No it has not, so let's set it here. */

        /* First verify that this is a legal length to copy. */
        if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING)
        {

            /* Invalid length, this will overrun the buffer. */

            /* Release the packet.  */
            nx_packet_release(packet_ptr);
    
            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);
    
            /* Return to caller.  */
            return;
        }

        memcpy(agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_current_octet_string, context_name_size);

        agent_ptr -> nx_snmp_agent_v3_context_name_size  = context_name_size;
    }  

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /****************************************************/
    /*            SET the PDU engine name               */
    /****************************************************/

    response_length =  _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid packet.  */
    if (response_length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response pointer forward.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Save the pointer to the response type.  */
    response_type_ptr =  response_buffer_ptr;

    /* Increment the sequence length.  */
    response_sequence_length =       response_sequence_length + response_length; 
    
    /* Increment the pdu length.  */
    response_pdu_length =            response_pdu_length + response_length;

    /****************************************************/
    /*            Get the PDU request type              */
    /****************************************************/
    length =  _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    agent_ptr -> nx_snmp_agent_request_get_type =  NX_FALSE;
    if ((request_type == NX_SNMP_GET_REQUEST) || 
        (request_type == NX_SNMP_GET_NEXT_REQUEST) ||
        (request_type == NX_SNMP_GET_BULK_REQUEST))
    {
         agent_ptr -> nx_snmp_agent_request_get_type =  NX_TRUE;
    }


    /****************************************************/
    /*            SET the PDU request type              */
    /****************************************************/
    response_length =  _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Increment the pdu length.  */
    response_pdu_length =  response_pdu_length + response_length;

    /****************************************************/
    /*            Get the PDU request ID                */
    /****************************************************/
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /****************************************************/
    /*            SET the PDU request ID                */
    /****************************************************/
    response_length =  _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Increment the pdu length.  */
    response_pdu_length =  response_pdu_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /* Save a pointer to the error string.  */
    error_ptr =  buffer_ptr;

    /****************************************************/
    /*            Get the PDU error information         */
    /****************************************************/
    /* This is actually used to derive the GETBULK information in SNMP V3 and above.  */
    length =  _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }


    /* Determine if the received packet size is too big.  */
    if (packet_ptr -> nx_packet_next)
    {

        /* Call the error handling response routine.  */
        _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Done, return to caller.  */
        return;
    }


    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /****************************************************/
    /*            SET the PDU error information         */
    /****************************************************/
    response_length =  _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Increment the pdu length.  */
    response_pdu_length =  response_pdu_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

    /****************************************************/
    /*            Get the PDU variable list length      */
    /****************************************************/
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length);

    /* Check for a valid packet.  */
    if (length == 0)
    {

        /* Increment the invalid packet error counter.  */
        agent_ptr -> nx_snmp_agent_invalid_packets++;

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the buffer pointer up.  */
    buffer_ptr =  buffer_ptr + length;

    /* The buffer pointer is moved by the length. Update buffer size */
    buffer_length -= (INT)length;

    /* At this point we have parsed the incoming SNMP request up to the first 
       variable.  */

    /* Remember the start of the response's variable list field.  */
    response_variable_list_ptr =  response_buffer_ptr;

    /* Setup the variable list response.  For now, the length will be zero.  We 
       will overwrite this with the actual length later.  */
    response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (response_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the packet.  */
        nx_packet_release(packet_ptr);

        /* Release the response packet too.  */
        nx_packet_release(response_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    response_buffer_ptr =  response_buffer_ptr + response_length;

    /* Adjust the response sequence length.  */
    response_sequence_length =  response_sequence_length + response_length;

    /* Increment the pdu length.  */
    response_pdu_length =  response_pdu_length + response_length;

    /* Adjust the response request type length.  */
    response_type_length =  response_type_length + response_length;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Process the variable binding list, line %d \n\r", __LINE__);
#endif

    /* At this point the response buffer is setup to exactly the same position the 
       SNMP Manager's input buffer is - right before the first variable.  We can
       now walk through the variable list to process each request and place the
       result in the response buffer.  */
    objects =              0;
    next_object =          NX_TRUE;
    current_repetitions =  max_repetitions;
    do
    {

        /* Determine if the next object should be retrieved.  */
        if (next_object)
        {

            /* Remember the start of the variable.  */
            variable_start_ptr =  buffer_ptr;

            /* Pickup the first SNMP Variable length.  */
            length =  _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length);

            /* Calculate the total variable size.  */
            total_variable_length =  variable_length + length;

            /* Move the buffer pointer up.  */
            buffer_ptr =  buffer_ptr + length;

            /* The buffer pointer is moved by the length. Update buffer size */
            buffer_length -= (INT)length;

            /* Now pickup the object ID.  */
            length =  _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length);

            /* Determine if the object retrieval was successful.  */ 
            if (length == 0) 
            {

                /* Increment the invalid packet error counter.  */
                agent_ptr -> nx_snmp_agent_invalid_packets++;

                /* Increment the internal error counter.  */
                agent_ptr -> nx_snmp_agent_internal_errors++;

                /* Release the packet.  */
                nx_packet_release(packet_ptr);

                /* Release the response packet.  */
                nx_packet_release(response_packet_ptr);

                /* Return to caller.  */
                return;
            }

            /* Move the buffer pointer up.  */
            buffer_ptr =  buffer_ptr + length;

            /* The buffer pointer is moved by the length. Update buffer size */
            buffer_length -= (INT)length;

            /* Default the value to NULL.  */
            agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type =  0;

            /* Determine if a value is present.  */
            if (length != variable_length)
            {

                /* Pickup the value associated with this variable.  */
               length =  _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length);

                /* Determine if the object value was successful.  */ 
                if (length == 0) 
                {

                    /* Increment the invalid packet error counter.  */
                    agent_ptr -> nx_snmp_agent_invalid_packets++;

                    /* Increment the internal error counter.  */
                    agent_ptr -> nx_snmp_agent_internal_errors++;

                    /* Send an SNMP version error response.  */
                    _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1);

                    /* Release the packet.  */
                    nx_packet_release(packet_ptr);

                    /* Release the response packet.  */
                    nx_packet_release(response_packet_ptr);

                    /* Return to caller.  */
                    return;
                }
            }
        }

        /* At this point, we are ready to call the appropriate application request handling routine.  
           It is responsible for extracting or placing information in the object data structure.  */
        if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                               &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        {

            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Call the application's GETNEXT routine.  */
            status =  (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                                   &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST)
        {
        
            /* Increment the total number of get variables.  */
            agent_ptr -> nx_snmp_agent_total_get_variables++;

            /* Clear the next object flag.  */
            next_object =  NX_FALSE;

            /* Call the application's GETNEXT routine.  */
            status =  (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                                   &(agent_ptr -> nx_snmp_agent_current_object_data));

            /* Decrement the number of non-repeaters.  */
            if (non_repeaters)
            {

                /* Decrement the number of non-repeaters.  */
                non_repeaters--;

                /* Set the next object flag to move to the next entry of the request.  */
                next_object =  NX_TRUE;
            }
            else 
            {

                /* Decrement the repetitions.  */
                if (current_repetitions)
                    current_repetitions--;

                /* Determine if there are more repetitions or if the end of MIB was detected.  */
                if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW))
                {

                    /* Reset the current repetition.  */
                    current_repetitions =  max_repetitions;

                    /* Set the next object flag to true.  */
                    next_object =  NX_TRUE;
                }
            }
        }
        else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        {

            /* Increment the total number of set variables.  */
            agent_ptr -> nx_snmp_agent_total_set_variables++;

            /* Call the application's SET routine.  */
            status =  (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, 
                                                               &(agent_ptr -> nx_snmp_agent_current_object_data));
        }
        else
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Error processing variable binding items (invalid request type %d). Line %d \n\r", request_type, __LINE__);
#endif
            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;
            
            /* Done, return to caller.  */
            return;
        }

        /* Check for an error status from the agent's request processing callback routine.  */
        if (status)
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Error processing variable binding get request callback. Line %d \n\r",  __LINE__);
#endif
            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Determine if the returning object is valid.  */
        if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || 
            (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.'))
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Error processing variable binding. Invalid object from get request callback. Line %d \n\r",  __LINE__);
#endif
            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }

        /* Now ensure the returning object type is valid.  */
        if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && 
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) &&
            (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW))
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Error processing variable binding (unknown object type). Line %d \n\r",  __LINE__);
#endif
            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Release the packet. */
            nx_packet_release(packet_ptr);

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Done, return to caller.  */
            return;
        }
        /* Everything is okay, place the object and object data into the response buffer.  */

        /* Remember the start of the variable response sequence.  */
        response_variable_ptr =  response_buffer_ptr;

        /* Clear the response variable size.  */
        response_variable_length =  0;

        /* Determine if there is enough room in the destination for the variable sequence.  */
        if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Setup the variable response sequence.  For now, the length will be zero.  We 
           will overwrite this with the actual length later.  */
        response_length =  _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Increment the internal error counter.  */
            agent_ptr -> nx_snmp_agent_internal_errors++;

            /* Release the packet.  */
            nx_packet_release(packet_ptr);

            /* Release the response packet too.  */
            nx_packet_release(response_packet_ptr);

            /* Return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Increment the pdu length.  */
        response_pdu_length =  response_pdu_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Place the object into the response buffer.  */
        response_length =  _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); 

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine.  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Increment the pdu length.  */
        response_pdu_length =  response_pdu_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Insert the object's data into the response buffer.  */
        response_length =  _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end);

        /* Check for a valid operation.  */
        if (response_length == 0)
        {

            /* Release the response packet.  */
            nx_packet_release(response_packet_ptr);

            /* Call the error handling response routine. This will release the packet  */
            _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects);

            /* Done, return to caller.  */
            return;
        }

        /* Move the response buffer pointer up.  */
        response_buffer_ptr =  response_buffer_ptr + response_length;

        /* Adjust the response sequence length.  */
        response_sequence_length =  response_sequence_length + response_length;

        /* Increment the pdu length.  */
        response_pdu_length =  response_pdu_length + response_length;

        /* Adjust the response request type length.  */
        response_type_length =  response_type_length + response_length;

        /* Adjust the response variable list size.  */
        response_variable_list_length =  response_variable_list_length + response_length;

        /* Adjust the response variable size.  */
        response_variable_length =  response_variable_length + response_length;

        /* Now update the response variable sequence with the actual variable length.  */
        _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end);

        /* Only update the source object information if the next object flag is set.  */
        if (next_object)
        {

            /* Adjust the pointer to the next variable.  */
            buffer_ptr =  variable_start_ptr + total_variable_length;

            /* Decrement the size of the variable list.  */
            variable_list_length =  variable_list_length - total_variable_length;

            /* Increment the object counter.  */
            objects++;
        }

    } while ((variable_list_length) || (next_object == NX_FALSE));


#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Variable binding processing completed\n\r");
#endif

    /* At this point, several response fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(response_header_ptr, response_header_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(response_security_ptr, response_security_length, response_packet_ptr -> nx_packet_data_end);
    if (encrypt_message == NX_FALSE)
    {
        _nx_snmp_utility_sequence_set_1byte(response_pdu_ptr, response_pdu_length, response_packet_ptr -> nx_packet_data_end);
    }
    _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end);

    /* Setup the security OCTET string length.  */

    /* Backup to the OCTET string for the security size.  */
    response_security_ptr =  response_security_ptr - 2;
    
    /* Account for the 4 byte Security Sequence field.  */
    response_security_length =  response_security_length + 4;

    /* Store the security size.  */
    response_security_ptr[1] =  (UCHAR) (response_security_length & 0xFF);

    /* Determine if privacy is required.  If so, encrypt the PDU and setup the response
       to have an encryption header.  */ 
    if (encrypt_message == NX_TRUE)
    {

        _nx_snmp_agent_encrypt_pdu(agent_ptr, &response_pdu_length, &response_sequence_length, 
                                   response_encryption_size_ptr, &response_sequence_ptr,
                                   response_packet_ptr -> nx_packet_data_end,
                                   &response_buffer_ptr, response_privacy_ptr);
    }

    /* Now the response packet's pointers must be setup so it can be sent.  */
    response_packet_ptr -> nx_packet_length =  (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr);
    response_packet_ptr -> nx_packet_append_ptr =  response_buffer_ptr;

    if (authenticate_message == NX_TRUE)
    {

        /* Yes, authentication is required.  */
        status = _nx_snmp_agent_add_auth_parameter(agent_ptr, response_packet_ptr, response_authentication_ptr);

        if (status != NX_SUCCESS)
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r",  __LINE__);
#endif
            /* Increment the authentication error counter.  */
            agent_ptr -> nx_snmp_agent_authentication_errors++;

            /* Release the report packet too.  */
            nx_packet_release(response_packet_ptr);

            /* Release the original request packet.  */
            nx_packet_release(packet_ptr);

            return;
        }
    }

    /* Release the original request packet.  */
    nx_packet_release(packet_ptr);

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_total_bytes_received +=  packet_ptr -> nx_packet_length;
    agent_ptr -> nx_snmp_agent_total_bytes_sent +=      response_packet_ptr -> nx_packet_length;
    if (request_type == NX_SNMP_ANS1_GET_REQUEST)
        agent_ptr -> nx_snmp_agent_get_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST)
        agent_ptr -> nx_snmp_agent_getnext_requests++;
    else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST)
        agent_ptr -> nx_snmp_agent_getbulk_requests++;
    else if (request_type == NX_SNMP_ANS1_SET_REQUEST)
        agent_ptr -> nx_snmp_agent_set_requests++;

    /* Increment the sent packet counter.  */
    agent_ptr -> nx_snmp_agent_packets_sent++;
    
    /* Increment the get responses sent counter.  */
    agent_ptr -> nx_snmp_agent_getresponse_sent++;

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Sending the response to SNMPv3 request on line %d.\n\r", __LINE__);
#endif

    /* Send the response packet back to the requesting SNMP manager.  */
    status =  nx_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, 
                                                agent_ptr -> nx_snmp_agent_current_manager_ip,
                                                agent_ptr -> nx_snmp_agent_current_manager_port);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(response_packet_ptr);
    }
}
#endif  /* NX_SNMP_DISABLE_V3 */


#ifndef NX_SNMP_DISABLE_V3
/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_report_send                      PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*    This function sends reports to the SNMP Manager in response to      */
/*    received requests. These are usually discovery requests, but can    */
/*    also be USM violations such as unknown username, unsupported        */
/*    security level or invalid boot data.                                */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    discovery_respond                     Reason for report             */
/*    buffer_length                         Size of buffer data           */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    nx_packet_allocate                    Allocate response packet      */ 
/*    nx_packet_release                     Release the packet            */ 
/*    nx_udp_socket_send                    Send the UDP packet           */ 
/*    _nx_snmp_utility_error_info_set       Set the error information     */ 
/*    _nx_snmp_utility_octet_set            Set the octet string          */ 
/*    _nx_snmp_utility_request_id_set       Set the request ID            */ 
/*    _nx_snmp_utility_request_type_set_multibyte                         */
/*                                          Set trap request type         */
/*    _nx_snmp_utility_sequence_set         Set the ANS.1 sequence        */ 
/*    _nx_snmp_utility_version_set          Set the SNMP version          */ 
/*    tx_time_get                           Get the time                  */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request       */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID  _nx_snmp_version_3_report_send(NX_SNMP_AGENT *agent_ptr, UCHAR *buffer_ptr, UINT report_respond, INT buffer_length)
{

UINT                status;
UINT                report_length;
NX_PACKET           *report_packet_ptr;
UCHAR               *report_buffer_ptr, *report_sequence_ptr, *report_header_ptr, *report_security_ptr;
UCHAR               *report_authentication_ptr = NX_NULL, *report_pdu_ptr, *report_type_ptr;
UINT                report_sequence_length, report_header_length, report_security_length, report_pdu_length, report_type_length;
UCHAR               *report_encryption_size_ptr = NX_NULL;
UCHAR               temp_string[NX_SNMP_DIGEST_SIZE];
UINT                packet_type;
UCHAR               *report_variable_list_ptr = NX_NULL;
UINT                report_variable_length = 0;
UINT                report_variable_list_length = 0;
UCHAR               *report_variable_ptr = NX_NULL;
ULONG               request_id;
UINT                temp, i;
UINT                length;
UINT                request_type;
UINT                request_length;
UINT                authenticate, encryption, send_reply;
UCHAR               report_security_level;


#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Processing the report...\n\r");
#endif

    /* Now prepare report message so we can process the report.  */

    packet_type = NX_UDP_PACKET;

    /* Allocate the packet for the SNMP report.  */
    status =  nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &report_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT);

    /* Determine if a report packet was allocated.  */
    if (status)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Report: error allocating packet 0x%x.\n\r", status);
#endif
        /* Increment the packet allocation error counter.  */
        agent_ptr -> nx_snmp_agent_allocation_errors++;

        /* Return to caller.  */
        return;
    }

    memset(report_packet_ptr -> nx_packet_prepend_ptr, 0, 
           (UINT)(report_packet_ptr -> nx_packet_data_end - report_packet_ptr -> nx_packet_prepend_ptr));

    /* Initialize the counters required for the length fields of the report packet.  */
    report_sequence_length =       0; 
    report_header_length =         0;
    report_security_length =       0;
    report_pdu_length =            0;
    report_type_length =           0;

    /* Setup a pointer to the report packet's buffer area.  */
    report_buffer_ptr =  report_packet_ptr -> nx_packet_prepend_ptr;

    _nx_snmp_agent_security_response_status(agent_ptr, &authenticate, &encryption, &send_reply);

    if (send_reply == NX_FALSE)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Report: received request with encryption set. Encryption not enabled on device; no report sent.\n\r");
#endif
        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        return;
    }

    /* We need to set our own security level in case the report security settings differ from the incoming request. */
    report_security_level = (UCHAR)authenticate;

    /* Find out if we need to decrypt this message. */
    if (encryption == NX_TRUE)
    {

        /* We do. Decrypt the data. We need to get the PDU data, request id and other data. */
        status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, NX_NULL, &report_encryption_size_ptr, &report_length, buffer_length);

        if (status != NX_SUCCESS)
        {

            /* Release the report packet.  */
            nx_packet_release(report_packet_ptr);

            return;
        }
    }

    /* Get the PDU sequence location.  */
    length =  _nx_snmp_utility_sequence_get(buffer_ptr, &temp, buffer_length);

    if (length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;  

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    buffer_ptr += length;
    buffer_length -= (INT)length;

    /* Get the SNMP v3 PDU context engine field location.  */
    length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string,
                                         sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length);

    if (length == 0)
    {
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    buffer_ptr += length;
    buffer_length -= (INT)length;

    /* Get the SNMP v3 PDU context name field location.  */
    length =  _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string,
                                         sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length);
    if (length == 0)
    {
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    buffer_ptr += length;
    buffer_length -= (INT)length;

    /* Pick up the SNMP Request type and location.  */
    length =  _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length);
    if (length == 0)
    {
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    buffer_ptr += length;
    buffer_length -= (INT)length;

    /* Get the SNMP Request ID.  We need this for our report. */
    length =  _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length);
    if (length == 0)
    {
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* This is also the report sequence pointer. Remember it since we are going to have to
       update it later with the actual length of the report.  */
    report_sequence_ptr =  report_buffer_ptr;

    /* First, write the sequence in the report packet.  A zero is written for now.  This will be 
       updated later.  */
    report_length =  _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /********************************************************/
    /*                      Set the version ID              */
    /********************************************************/
    report_length =  _nx_snmp_utility_version_set(report_buffer_ptr, NX_SNMP_VERSION_3, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Save the pointer to the global header.  */
    report_header_ptr =  report_buffer_ptr;

    /* Write the sequence for the global header in the report packet.  A zero is written for now.  
       This will be updated later.  */
    report_length =  _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /********************************************************/
    /*                      Set the request ID              */
    /********************************************************/

    /* This must match the request specified by the discovery request.  */
    report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the header sequence length.  */
    report_header_length =  report_header_length + report_length;

    /********************************************************/
    /*              Set the maximum message size            */
    /********************************************************/
    report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the header sequence length.  */
    report_header_length =  report_header_length + report_length;

    /********************************************************/
    /*                  Set the security options            */
    /********************************************************/
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, (UCHAR *)&(report_security_level), 1, report_packet_ptr -> nx_packet_data_end);

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Setting report security level to 0x%x\n\r", report_security_level);
#endif

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the header sequence length.  */
    report_header_length =  report_header_length + report_length;

    /********************************************************/
    /*                  Set the security type               */
    /********************************************************/
    report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the header sequence length.  */
    report_header_length =  report_header_length + report_length;

    /* At this point, we have successfully built the security header.  Now, we need to build 
       the security parameters field.  */

    /* First setup the octet string field.  */
    report_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
    report_buffer_ptr[1] =  0;

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + 2;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + 2;

    /* Remember the security header pointer.  */
    report_security_ptr =  report_buffer_ptr;

    report_length =  _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /********************************************************/
    /*                   Set the context engine             */
    /********************************************************/
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /********************************************************/
    /*                  Set the boot count                  */
    /********************************************************/
    if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM)
    {

        /* Set boot count to zero for discovery requests. */
        report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);
    }
    else
    {

        /* Use the current SNMP boot count for all others. */
        report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, report_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /* Start the time (in ticks) since the previous reboot. */
    agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);

    /********************************************************/
    /*                  Set the boot time                   */
    /********************************************************/
    if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM)
    {

        /* Set boot time to zero. */
        report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);
    }
    else
    {

        /* Start the time (in ticks) since the previous reboot. */
        agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time =  (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE);
        /* Use the current SNMP boot time. */
        report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, report_packet_ptr -> nx_packet_data_end);
    }
    
    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /********************************************************/
    /*                Set the security user name            */
    /********************************************************/

    /* Set the security user name as specified in the request message.  */
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, report_packet_ptr -> nx_packet_data_end);


    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /* Initialize the temporary string to zero. */
    for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
      temp_string[i] =  0;
    /********************************************************/
    /*     Set the security authentication parameter        */
    /********************************************************/

    if (authenticate == NX_TRUE)
    {



#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to zero in report. (Line %d) \n\r", __LINE__);
#endif
        /* All set to add an authentication parameter. For now, set to all zeros. */
        report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, report_packet_ptr -> nx_packet_data_end);

        /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE (12) byte authorization parameter.  */
        report_authentication_ptr =  report_buffer_ptr + 2;        
    }
    else
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to empty. \n\r");
#endif
        /* No security enabled so set this as an empty parameter. */
        report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end);
    }

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /* Set the Privacy Parameter field to empty (encryption/privacy not used in reports).  */
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the security sequence length.  */
    report_security_length =  report_security_length + report_length;

    /* Remember the PDU sequence pointer.  */
    report_pdu_ptr =  report_buffer_ptr;

    /* Now set the sequence of the PDU.  We will replace this sequence type with 'opaque'
       if encryption is required later. */
    report_length =  _nx_snmp_utility_sequence_set(report_pdu_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /********************************************************/
    /*                  Set the Context Engine ID           */
    /********************************************************/

    /* The Context Engine ID should be the same as the msgAuthoritativeEngine ID since there is no proxy. */
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, 
                                                agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Now setup the PDU context name field - it is a null field in the response.  */
    report_length =  _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Remember the type field's starting address.  */
    report_type_ptr =  report_buffer_ptr;

    /* Now setup the message type field.  */
    report_length =  _nx_snmp_utility_request_type_set_multibyte(report_buffer_ptr, NX_SNMP_ANS1_REPORT_REQUEST, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /********************************************************/
    /*                  Set PDU request ID                  */
    /********************************************************/
    /* Set the PDU request to zero instead of matching the request if the request is encrypted. 
       Otherwise the request ID must match the request specified by the browser request. */
    if (encryption)
    {
        request_id = 0;
    }
    
    /* Set the PDU request ID.  */
    report_length =  _nx_snmp_utility_request_id_set(report_buffer_ptr, request_id, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the report type length.  */
    report_type_length =  report_type_length + report_length;

    /********************************************************/
    /*                  Set the error info                  */
    /********************************************************/
    report_length =  _nx_snmp_utility_error_info_set(report_buffer_ptr, 0, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the report type length.  */
    report_type_length =  report_type_length + report_length;

    /* Mark the beginning of the variable list. */
    report_variable_list_ptr =  report_buffer_ptr; 

    /********************************************************/
    /*                  Set up the variable list            */
    /********************************************************/

    /* Now setup the sequence for the variable list.  This is set to zero for now.  */                                        
    report_length =  _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the report buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the report sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Adjust the PDU sequence length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the report type length.  */
    report_type_length =  report_type_length + report_length;

    /* Remember the start of the variable response sequence.  */
    report_variable_ptr =  report_buffer_ptr;

    /* Clear the response variable size.  */
    report_variable_length =  0;

    /* Determine if there is enough room in the destination for the variable sequence.  */
    if ((report_buffer_ptr + 4) >= report_packet_ptr -> nx_packet_data_end)
    {

        /* Release the response packet.  */
        nx_packet_release(report_packet_ptr);

        /* Done, return to caller.  */
        return;
    }

    /********************************************************/
    /*    Initialize variable response sequence to zero     */
    /********************************************************/

    /*  We will overwrite this with the actual length later.  */
    report_length =  _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the response sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Increment the pdu length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the response request type length.  */
    report_type_length =  report_type_length + report_length;

    /********************************************************/
    /*        Adjust the response variable list size.       */
    /********************************************************/

    /* Adjust the response variable list size.  */
    report_variable_list_length =  report_variable_list_length + report_length;

    /********************************************************/
    /*                 Set the report OID object            */
    /********************************************************/

    if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM)
    {
        /* This report is responding to a discovery request. */
        memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID, 
               sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID));

        status =  _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_engineid_count), 
                                              &agent_ptr -> nx_snmp_agent_current_object_data);

    }
    else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM)
    {
        /* This report is responding to a mismatch ("unsupported") in security level. */
        memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC, 
               sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC));

        status =  _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unsupported_sec_count), 
                                              &agent_ptr -> nx_snmp_agent_current_object_data);
    }
    else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM)
    {
        
        /* This report is responding to an unknown user name. */
        memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME, 
               sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME));

        status =  _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_username_count), 
                                              &agent_ptr -> nx_snmp_agent_current_object_data);
    }
    else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM)
    {
        
        /* This report is responding to invalid boot time or boot count data received. */
        memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME, 
               sizeof(NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME));

        status =  _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_mismatched_time_count), 
                                              &agent_ptr -> nx_snmp_agent_current_object_data);
    }
    else
    {

        /* Unknown report type. Abort! */

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Unknown report parameter %d. Abort report processing. \n\r", report_respond);
#endif
        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);
    
        return;
    }

    /* Check for a valid operation.  */
    if (status != NX_SUCCESS)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the response packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* Increment the total number of get variables.  */
    agent_ptr -> nx_snmp_agent_total_get_variables++;

    /* Determine if the returning object is valid.  */
    if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || 
        (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.'))
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Invalid object from application GET routine on line %d.\n\r", __LINE__);
#endif
        /* Release the response packet.  */
        nx_packet_release(report_packet_ptr);

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Done, return to caller.  */
        return;
    }

    /* Now ensure the returning object type is valid.  */
    if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && 
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && 
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) &&
        (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW))
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Invalid object type (%d) from application GET routine on line %d.\n\r", 
                   agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type, __LINE__);
#endif

        /* Release the response packet.  */
        nx_packet_release(report_packet_ptr);

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Done, return to caller.  */
        return;
    }

    /* Place the object into the response buffer.  */
    report_length =  _nx_snmp_utility_object_id_set_1byte(report_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, report_packet_ptr -> nx_packet_data_end); 

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Release the response packet.  */
        nx_packet_release(report_packet_ptr);

        /* Done, return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the response sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Increment the pdu length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the response request type length.  */
    report_type_length =  report_type_length + report_length;

    /* Adjust the response variable list size.  */
    report_variable_list_length =  report_variable_list_length + report_length;

    /* Adjust the response variable size.  */
    report_variable_length =  report_variable_length + report_length;

    /* Insert the object's data into the response buffer.  */
    report_length =  _nx_snmp_utility_object_data_set(report_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Release the response packet.  */
        nx_packet_release(report_packet_ptr);

        /* Done, return to caller.  */
        return;
    }

    /* Move the response buffer pointer up.  */
    report_buffer_ptr =  report_buffer_ptr + report_length;

    /* Adjust the response sequence length.  */
    report_sequence_length =  report_sequence_length + report_length;

    /* Increment the pdu length.  */
    report_pdu_length =  report_pdu_length + report_length;

    /* Adjust the response request type length.  */
    report_type_length =  report_type_length + report_length;

    /* Adjust the response variable list size.  */
    report_variable_list_length =  report_variable_list_length + report_length;

    /* Adjust the response variable size.  */
    report_variable_length =  report_variable_length + report_length;

    /* Now update the response variable sequence with the actual variable length.  */
    report_length =  _nx_snmp_utility_sequence_set(report_variable_ptr, report_variable_length, report_packet_ptr -> nx_packet_data_end);

    /* Check for a valid operation.  */
    if (report_length == 0)
    {

        /* Increment the internal error counter.  */
        agent_ptr -> nx_snmp_agent_internal_errors++;

        /* Release the report packet too.  */
        nx_packet_release(report_packet_ptr);

        /* Return to caller.  */
        return;
    }

    /* At this point, several report fields need to be updated with actual lengths.  */
    _nx_snmp_utility_sequence_set(report_sequence_ptr, report_sequence_length, report_packet_ptr -> nx_packet_data_end); 
    _nx_snmp_utility_sequence_set(report_header_ptr, report_header_length, report_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(report_security_ptr, report_security_length, report_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(report_pdu_ptr, report_pdu_length, report_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_sequence_set(report_variable_list_ptr, report_variable_list_length, report_packet_ptr -> nx_packet_data_end);
    _nx_snmp_utility_request_type_set_multibyte(report_type_ptr, NX_SNMP_ANS1_REPORT_REQUEST, report_type_length, report_packet_ptr -> nx_packet_data_end);

    /* Now the report packet's pointers must be setup so it can be sent.  */
    report_packet_ptr -> nx_packet_length =  (ULONG)(report_buffer_ptr - report_packet_ptr -> nx_packet_prepend_ptr);
    report_packet_ptr -> nx_packet_append_ptr =  report_buffer_ptr;

    /********************************************************/
    /*           Set the authorization parameter            */
    /********************************************************/

    /* Also adjust the length of the security parameters field. */
    report_security_ptr =  report_security_ptr - 2;

    /* Adjust the report security length.  */
    report_security_length =  report_security_length + 4;

    /* Store the security string size.  */
    report_security_ptr[1] =  (UCHAR) (report_security_length & 0xFF);

    /* Update various statistics.  */
    agent_ptr -> nx_snmp_agent_reports_sent++;

    /* Increment the sent packet counter.  */
    agent_ptr -> nx_snmp_agent_packets_sent++;

    /* Set the authentication parameter if we have determined it needs to be set, and only if we 
       have a valid user name. (Otherwise there would be no shared key for the other side to check
       our authentication.)*/
    if ((authenticate == NX_TRUE) && (report_respond != NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM))
    {

        /* Fill in the authentication parameter.  */
        status = _nx_snmp_agent_add_auth_parameter(agent_ptr, report_packet_ptr, report_authentication_ptr);

        if (status != NX_SUCCESS)
        {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
            NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r",  __LINE__);
#endif

            /* Increment the authentication error counter.  */
            agent_ptr -> nx_snmp_agent_authentication_errors++;

            /* Release the original request packet.  */
            nx_packet_release(report_packet_ptr);

            return;
        }
    }

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
    NX_SNMPV3_DBG_PRINTF("Sending the report on line %d.\n\r", __LINE__);
#endif

    /* Send the report packet back to the requesting SNMP manager.  */
    status = nx_udp_socket_send(&(agent_ptr ->  nx_snmp_agent_socket), report_packet_ptr, 
                                                agent_ptr -> nx_snmp_agent_current_manager_ip, 
                                                agent_ptr -> nx_snmp_agent_current_manager_port);

    /* Determine if the packet needs to be released. */
    if (status)
    {

        /* Release packet.  */
        nx_packet_release(report_packet_ptr);
    }


    /* Return to caller.  */
    return;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_add_auth_parameter                   PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*   This function updates the specified SNMPv3 response with an          */
/*   authentication parameter.                                            */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    response_packet_ptr                   Pointer to reply message data */
/*    response_authentication_ptr           Pointer to authentication     */
/*                                            parameter in the reply      */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Successfully added            */
/*                                              authentication parameter  */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    _nx_md5_update                        Calculate MD5 message digest  */
/*    _nx_md5_digest_calculate              MD5 digest calculated         */
/*    _nx_md5_initialize                    Prepare data for MD5 calc     */
/*    _nx_sha_update                        Calculate SHa message digest  */
/*    _nx_sha__digest_calculate             SHa digest calculated         */
/*    _nx_sha__initialize                   Prepare data for SHa calc     */
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request reply */ 
/*    _nx_snmp_version_3_report_send        Process SNMP v3 report        */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_agent_add_auth_parameter(NX_SNMP_AGENT *agent_ptr, NX_PACKET *response_packet_ptr, UCHAR *response_authentication_ptr)
{

UINT  i;
UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE];


        /* Determine which authentication is required.  */
        if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && 
            ((agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY))
        {

            /* Copy the base MD5 key into key1.  */
            for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base MD5 key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Calculate prepend Key1.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data));

            /* Prepend Key2 to the result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2);
        }
        else if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && 
            (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY))
        {

            /* Copy the base SHA key into key1.  */
            for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++)
            {

                /* Copy a byte of the base SHA key.  */
                key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i];
            }
            
            /* Extend key1 to 64 bytes.  */
            for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key1[i] =  0;
            }

            /* Create key1 and key2.  */
            for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++)
            {
                key2[i] = key1[i] ^ 0x5C;
                key1[i] = key1[i] ^ 0x36;
            }

            /* Calculate the MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Calculate prepend Key1.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE);
    
            /* Calculate the message.  */    
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length);

            /* Final calculation of the first pass.   */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1);

            /* Prepare to calculate the final MAC.  */
            _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data));

            /* Prepend Key2 to the result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE);

            /* Calculate the previous result.  */
            _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE);

            /* Calculate the final MAC. */
            _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2);
        }
        else
        {

            /* Return to caller.  */
            return NX_SNMP_UNSUPPORTED_AUTHENTICATION;
        }

        /* At this point, key2 contains the computed digest of the message.  This needs to be 
           placed in the outgoing message.  */

        /* Loop to setup the outgoing digest.  */
        for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++)
        {

            /* Copy the next byte of digest into the response buffer.  */
            response_authentication_ptr[i] =  key2[i];
        }

        return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_encrypt_pdu                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*   This function encrypts data pointed to by the response buffer pointer*/
/*   and updates the necessary SNMPv3 header size in the header sequence  */
/*   data.                                                                */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    [These pointers pertain to the encrypted data to send:]             */
/*    response_pdu_length                   Size of the PDU data          */
/*    response_sequence_length              Size of the response sequence */
/*    response_encryption_size_ptr          Size of encryption data       */
/*    response_sequence_ptr                 Pointer to the SNMPv3 sequence*/
/*    response_buffer_ptr                   Pointer to the SNMPv3 response*/
/*    response_privacy_ptr                  Pointer to privacy parameter  */
/*    response_length                       Updated size of response      */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Data successfully decrypted   */ 
/*    NX_SNMP_INVALID_PDU_ENCRYPTION        Invalid encrypted data        */
/*    NX_SNMP_INVALID_ENCRYPT_LENGTH        Decryption processing error   */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request reply */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/

UINT _nx_snmp_agent_encrypt_pdu(NX_SNMP_AGENT *agent_ptr, UINT *response_pdu_length, UINT *response_sequence_length, UCHAR *response_encryption_size_ptr,
                               UCHAR **response_sequence_ptr, UCHAR *response_sequence_buffer_end, UCHAR **response_buffer_ptr, UCHAR *response_privacy_ptr)
{

UINT  i, j;
UINT  padding = 0;
UCHAR *temp_ptr;
UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE];
UINT  pdu_sequence_length;
UINT  adjusted_pdu_length;

    if (response_pdu_length != NX_NULL) 
    {
    
        /* Determine if any padding needs to be applied - account for the
           four bytes of header information on the PDU.  */
        padding =  ((*response_pdu_length+7)/8)*8 - *response_pdu_length;
    
        /* Add the padding the response PDU length and the response sequence length.  */
        *response_pdu_length =  *response_pdu_length + padding;
        *response_sequence_length =  *response_sequence_length + padding;

        /* Use a work pointer to initialize the padding buffer. */
        temp_ptr = *response_buffer_ptr;
    
        /* Clear the end of the response message...  just to be nice!  */
        for (i = 0; i < padding; i++)
        {
    
            /* Clear byte at the end of the response.  */
            *temp_ptr++ =  0;
        }

        adjusted_pdu_length = *response_pdu_length;
    }
    else
    {
        /* Set the temp ptr to where the PDU starts in the request packet. */
        temp_ptr = pdu_buffer_ptr;
        adjusted_pdu_length = pdu_length;
    }

    /* If this is not for our outgoing response e.g. we are re-encrypting the received packet as part 
       of an error message, use the length from that packet. */
    if ((response_encryption_size_ptr == NX_NULL) || (response_pdu_length == NX_NULL))
    {

        pdu_sequence_length = pdu_length; 
    }
    else
    {
    
        /* We need to set the PDU "inner" sequence length; it comes just after the main PDU sequence header. */
        pdu_sequence_length = *response_pdu_length - 4;

        /* Do not include padding in the inner pdu size! */
        pdu_sequence_length = pdu_sequence_length - padding;
    }

    if ((response_encryption_size_ptr != NX_NULL) && (response_pdu_length != NX_NULL))
    {
    
        /* Now we set the PDU "inner" sequence header. Use the multibyte sequence 0x30 82 xx yy format. 
           Note that calling function has already set the pointer for writing encyrpted PDU data past this
           inner header.  */
        response_encryption_size_ptr[2] =  0x30;
        response_encryption_size_ptr[3] =  ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES;
        response_encryption_size_ptr[4] =  (UCHAR) ((pdu_sequence_length >> 8) & 0xFF);
        response_encryption_size_ptr[5] =  (UCHAR) (pdu_sequence_length & 0xFF);
    
        /* Update our response buffer pointer. */
        *response_buffer_ptr = temp_ptr;
    
        response_encryption_size_ptr[0] =  (UCHAR) ((*response_pdu_length >> 8) & 0xFF);
        response_encryption_size_ptr[1] =  (UCHAR) (*response_pdu_length & 0xFF);
    
        /* Update the total response sequence length again. */
        _nx_snmp_utility_sequence_set(*response_sequence_ptr, *response_sequence_length, response_sequence_buffer_end);
    }

    /* Increment the salt counter.  */
    agent_ptr -> nx_snmp_agent_v3_context_salt_counter++;

    /* Build the salt value for the encryption.  */
    key1[0] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF);
    key1[1] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF);
    key1[2] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >>  8) & 0xFF);
    key1[3] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF);
    key1[4] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF);
    key1[5] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF);
    key1[6] =  (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >>  8) & 0xFF);
    key1[7] =  (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF);


    if (response_privacy_ptr != NX_NULL)
    {
    
        /* Loop to store the salt in the privacy field.  */
        for (i = 0; i < 8; i++)
        {
    
            /* Store a byte of the salt.  */
            response_privacy_ptr[i] =  key1[i];
        }
    }

    /* Setup pointer to the actual PDU.  */
    if (response_encryption_size_ptr)
    {
        temp_ptr =  response_encryption_size_ptr + 2;
    }

    /* Make the Initialization Vector (IV).  */
    for (i = 0; i < 8; i++)
    {

        key2[i] =  (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key[8+i] ^ key1[i];
    }

    /* Setup the DES.  */
    _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key);

    /* Set up the first input block - use the IV for the first block.  */
    for (i = 0; i < 8; i++)
    {

        key1[i] =  temp_ptr[i] ^ key2[i];
    } 

    /* Encrypt the first 8 bytes.  */
    _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]);

    /* Loop to encrypt the rest of the PDU.  */
    j =  8;
    do
    {

        /* Setup the next input block.  */
        for (i = 0; i < 8; i++)
        {

            key1[i] =  temp_ptr[j+i] ^ temp_ptr[(j-8)+i];
        }

        /* Encrypt the next 8 bytes.  */
        _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]);

        /* Move the major index forward.  */
        j =  j + 8;

    } while (j < adjusted_pdu_length);

    return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_decrypt_pdu                          PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*   This function decrypts the data pointed to by the buffer pointer     */
/*   input. If the input response buffer pointer is not null, it will set */
/*   up the initial sequence header for the encrypted data around the     */
/*   msgData header                                                       */ 
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*    buffer_ptr                            Pointer to data to decrypt    */
/*    response_buffer_ptr                   Pointer to response to send   */
/*    [If response_buffer_ptr is null, these have no effect:]             */
/*    response_encryption_size_ptr          Pointer to encrypted data in  */
/*                                             response                   */
/*    response_length                       Size of encrypted data so far */
/*    buffer_length                         Size of buffer data           */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    NX_SUCCESS                            Data successfully decrypted   */ 
/*    NX_SNMP_INVALID_PDU_ENCRYPTION        Invalid encrypted data        */
/*    NX_SNMP_INVALID_ENCRYPT_LENGTH        Decryption processing error   */ 
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_process            Process SNMP v3 request reply */ 
/*    _nx_snmp_version_3_report_send        PRocess SNMP v3 report        */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/

UINT _nx_snmp_agent_decrypt_pdu(NX_SNMP_AGENT *agent_ptr, UCHAR **buffer_ptr, UCHAR *response_buffer_ptr,  
                                UCHAR **response_encryption_size_ptr, UINT *response_length, INT buffer_length)
{

UINT  i, j, encrypted_size;
UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE];
UCHAR *temp_ptr;


    *response_length = 0;
    temp_ptr = *buffer_ptr;

    /* Decrypt the source PDU and setup the response to have an encryption header.  */ 
    if (temp_ptr[0] != NX_SNMP_ANS1_OCTET_STRING)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Encryption error (no privacy key in the request). Line %d \n\r", __LINE__);
#endif
        /* Return to caller.  */
        return NX_SNMP_INVALID_PDU_ENCRYPTION;
    }

    /* Pickup the encrypted PDU size.  */
    if (temp_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES)
    {

        UINT temp = temp_ptr[1] & 0x7F;
        if (temp == 2)
        {
        
            /* Two byte octet string.  */
            encrypted_size =  (((UINT) temp_ptr[2]) << 8) | ((UINT) temp_ptr[3]);

            /* Move the buffer pointer up to the actual encrypted PDU contents.  */
            temp_ptr =  temp_ptr + 4;
        }
        else if (temp == 1)
        {

            /* One byte octet string e.g. 0x04 0x81 0xXY */
            encrypted_size =  (UINT) temp_ptr[2];

            /* Move the buffer pointer up to the actual encrypted PDU contents.  */
            temp_ptr =  temp_ptr + 3;

        }
        else
        {
            /* Either null or too big. Invalid size type.*/
            return NX_SNMP_ERROR_WRONGENCODING;
        }
    }
    else
    {

        /* One byte octet string.  */
        encrypted_size =  (UINT) temp_ptr[1];

        /* Move the buffer pointer up to the actual encrypted PDU contents.  */
        temp_ptr =  temp_ptr + 2;

    }

    /* Check for invalid buffer size. */
    if ((INT)encrypted_size > buffer_length)
    {

        /* Invalid buffer size. */
        return NX_SNMP_INVALID_PDU_ENCRYPTION;
    }

    /* Determine if the length is valid.  */
    if (encrypted_size % 8)
    {

#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE
        NX_SNMPV3_DBG_PRINTF("Encryption error (invalid length).Drop the request. Line %d \n\r", __LINE__);
#endif
        /* Return to caller.  */
        return NX_SNMP_INVALID_ENCRYPT_LENGTH;
    }

    /* Create the Initialization Vector (IV).  */
    for (i = 0; i < 8; i++)
    {

        key2[i] =  (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key[8+i] ^ agent_ptr -> nx_snmp_agent_v3_security_privacy[i];
    }

    /* Initialize the DES component. */
    _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key);

    /* Decrypt the first 8 bytes.  */
    _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), temp_ptr, key1);

    /* XOR with the IV.  */
    for (i = 0; i < 8; i++)
    {
    
        /* XOR a byte of the IV.  */
        key1[i] =  key1[i] ^ key2[i];
    }

    /* Loop to decrypt the entire PDU.  */
    j = 8;
    do
    {

        /* Decrypt the next 8-byte block.  */
        _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &temp_ptr[j], key2);

        /* XOR with the previous encrypted 8-byte block.  */
        for (i = 0; i < 8; i++)
        {

            /* XOR result with previous block.  */
            key2[i] =  key2[i] ^ temp_ptr[(j-8)+i];

            /* Copy a byte of the decrypted block over the source.  */
            temp_ptr[(j-8)+i] =  key1[i];

            /* Save this byte of the new decrypted block.  */
            key1[i] =  key2[i];
        }

        /* Move j up to the next 8 octet sequence.  */
        j = j + 8;
    } while (j < encrypted_size);

    /* Flush the last block out to the buffer.  */
    for (i = 0; i < 8; i++)
    {

        /* Copy a byte of the decrypted block over the source.  */
        temp_ptr[(j-8)+i] =  key1[i];
    }

    *buffer_ptr = temp_ptr;

     /* If the caller is going to encrypt its response it will send a non null response buffer pointer. */
     if (response_buffer_ptr != NX_NULL)
     {
     
         /* Now setup the response buffer to encapsulate the encrypted PDU.  Note that
            the actual encryption will be done after the complete response has been
            formed.  */
         response_buffer_ptr[0] =  NX_SNMP_ANS1_OCTET_STRING;
         response_buffer_ptr[1] =  0x82;
         response_buffer_ptr[2] =  0x00;
         response_buffer_ptr[3] =  0x00;

         /* Save the response encryption size pointer.  This will be filled in below
            as we build the message.  */
         *response_encryption_size_ptr =  response_buffer_ptr + 2; 

         *response_length = 4 ; 
     }

     return NX_SUCCESS;
}


/**************************************************************************/ 
/*                                                                        */ 
/*  FUNCTION                                               RELEASE        */ 
/*                                                                        */ 
/*    _nx_snmp_agent_security_response_status             PORTABLE C      */ 
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */ 
/*                                                                        */ 
/*   This function determines how to set authentication and privacy       */
/*   parameters in the USM header.                                        */
/*                                                                        */ 
/*  INPUT                                                                 */ 
/*                                                                        */ 
/*    agent_ptr                             Pointer to SNMP agent         */
/*                                                                        */ 
/*  OUTPUT                                                                */ 
/*                                                                        */ 
/*    *authenticate                         If true, authentication       */
/*                                             parameter should be set    */ 
/*    *encryption                           If true, privacy  parameter   */
/*                                             should be set              */ 
/*    *send_reply                           If not true, no reply or      */
/*                                             report should be sent      */
/*                                                                        */ 
/*  CALLS                                                                 */ 
/*                                                                        */ 
/*    None                                                                */ 
/*                                                                        */ 
/*  CALLED BY                                                             */ 
/*                                                                        */ 
/*    _nx_snmp_version_3_report_send        PRocess SNMP v3 report        */ 
/*                                                                        */ 
/*  RELEASE HISTORY                                                       */ 
/*                                                                        */ 
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
VOID _nx_snmp_agent_security_response_status(NX_SNMP_AGENT *agent_ptr, UINT *authenticate, UINT *encryption, UINT *send_reply)
{


    /* Initialize the security parameters to off. */
    *encryption = NX_FALSE;
    *authenticate = NX_FALSE;

    /* In all but one or two cases we always send a reply. Initialize to true. */
    *send_reply = NX_TRUE;

    /* Check if the incoming request specifies encryption (privacy). */
    if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY ) >= 2) 
    {

        /* It is. Check if the SNMP agent has created an encryption key. */
        if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL)        
        {

            /* We cannot decrypt the incoming message, (need the request ID), so we cannot send a reply. */
            *send_reply = NX_FALSE;

            return;
        }

        /* Ok to apply privacy security level. */
        *encryption = NX_TRUE;
    }
    else
    {

        /* Incoming message does not specify privacy. */

        /* Check if the SNMP agent has created an encryption key. */
        if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL)        
        {

            /* It has not.  The SNMP agent is not configured for privacy here. All good. */
        }
        /* else
             Same result, indicate no privacy applied to our response. */

    }

    /* Now if the incoming message security level is set for authentication regardless 
       of matching privacy levels. */
    if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) 
    {

        /* It is. Check if the SNMP agent has created an authentication key. */
        if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL)        
        {

            /* Ok to authenticate (even if not going apply privacy). */
            *authenticate = NX_TRUE;   
        }
        /*else
             Cannot authenticate, but we will still send a reply. */
    }

    return;
}

#endif /*NX_SNMP_DISABLE_V3 */


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_snmp_asn1_tlv_block_parse                       PORTABLE C      */
/*                                                           6.0          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Yuxin Zhou, Microsoft Corporation                                   */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function parses an ASN.1 type-length-value (TLV) block for use */
/*    by the SNMP Agent parsing data received from the browser.           */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    buffer                                Pointer to data to be parsed  */
/*    buffer_length                         Size of input buffer          */
/*    tlv_type                              Return block type             */
/*    tlv_tag_class                         Return class of the tag       */
/*    tlv_length                            Return parsed length          */
/*    tlv_data                              Return pointer to block data  */
/*    header_length                         Return length of block itself */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_snmp_utility_object_get           Extract data from sender      */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
/*                                                                        */
/**************************************************************************/
UINT _nx_snmp_utility_tlv_block_parse(UCHAR *buffer, INT buffer_length, USHORT *tlv_type,
                                      USHORT *tlv_tag_class, ULONG *tlv_length,
                                      UCHAR **tlv_data, ULONG *header_length)
{
UINT   current_index = 0;
USHORT current_tag;
ULONG  length;
ULONG  length_bytes;


    /* Check the buffer length.  */
    if ((INT)current_index >= buffer_length)
    {
        return(NX_SNMP_ERROR_WRONGLENGTH);
    }

    current_tag = buffer[current_index];

    /*  Handle multi-byte encoded tags. */
    if ((current_tag & NX_SNMP_ASN_TAG_MULTIBYTE_MASK) == NX_SNMP_ASN_TAG_MULTIBYTE_MASK)
    {
        return(NX_SNMP_MULTIBYTE_TAG_UNSUPPORTED);
    }
    else
    {
        *header_length = 1;
    }

    /* Get the class of the tag so we can return it. */
    *tlv_tag_class = (USHORT)((current_tag & NX_SNMP_ASN_TAG_CLASS_MASK) >> 6);

    /* Make sure we have a valid tag class. */
    if (*tlv_tag_class == NX_SNMP_ASN_TAG_CLASS_PRIVATE)
    {
        /* The tag class is invalid, return error. */
        return(NX_SNMP_INVALID_TAG_CLASS);
    }

    /* The caller actually handles what happens based on the tag type. */
    if (current_tag & NX_SNMP_ASN_TAG_CONSTRUCTED_MASK)
    {
        current_tag = current_tag & (USHORT)(~NX_SNMP_ASN_TAG_CONSTRUCTED_MASK);
    }

    /* Clear out the class and constructed bits before returning the tag value. */
    *tlv_type = current_tag & NX_SNMP_ASN_TAG_MASK;
    current_index++;

    /* Check the buffer length.  */
    if ((INT)current_index >= buffer_length)
    {
        return(NX_SNMP_ERROR_WRONGLENGTH);
    }

    if (current_tag == NX_SNMP_ANS1_NULL)
    {
        /*  If tag is NULL, there is no length byte, just a value of zero, */
        *tlv_length = 1;

        /* Set the data pointer and return. */
        *tlv_data = &buffer[current_index];

        return(NX_SUCCESS);
    }

    /* Handle the length. */
    length = buffer[current_index];
    current_index++;
    *header_length = *header_length + 1;

    /* Check for multi-byte length by looking at the top bit of the length byte. */
    if (length & 0x80)
    {
        /* Multi-byte length:
           > 127, high bit is set, and lower 7 bits becomes the number of following bytes of *length*
           so 841 bytes of Value is encoded as 0x82, 0x03, 0x49 (0x82 = 2 bytes of length, 0x0349 = 841).
         */

        /*  Mask off top bit to get the number of bytes in length. */
        length_bytes = length & 0x7F;
        length = 0;

        /*  Check for length too big to handle. */
        if (length_bytes > 4)
        {

            return(NX_SNMP_ASN1_LENGTH_TOO_LONG);
        }

        /* Update header length. */
        *header_length = *header_length + length_bytes;

        /* Check the buffer length.  */
        if ((INT)(current_index + length_bytes) > buffer_length)
        {
            return(NX_SNMP_ERROR_WRONGLENGTH);
        }

        while (length_bytes > 0)
        {
            /* Shift length one byte up and add in next byte. */
            length <<= 8;
            length += buffer[current_index];

            /* Advance our index by one byte. */
            current_index++;
            length_bytes--;
        }
    }
    else
    {
        /* Single-byte length:
           <= 127 (7 bits), length is the number of bytes of Value */
        *tlv_length = length;
    }

    /* Set the length to return to caller. */
    *tlv_length = length;

    /* Check the buffer length.  */
    if ((INT)current_index >= buffer_length)
    {
        return(NX_SNMP_ERROR_WRONGLENGTH);
    }

    /*  Now, we can set the tld value */
    *tlv_data = &buffer[current_index];

    return(NX_SUCCESS);
}


